flutter異常的捕獲方式

App異常,就是應(yīng)用代碼的異常,通常由未處理應(yīng)用層其他模塊所拋出的異常引起。根據(jù)異常代碼的執(zhí)行時(shí)序,App異??梢苑譃閮深?,即同步異常和異步異常:同步異常可以通過try-catch機(jī)制捕獲,異步異常則需要采用Future提供的catchError語句捕獲

//使用try-catch捕獲同步異常
try {
  throw StateError('This is a Dart exception.');
}
catch(e) {
  print(e);
}

//使用catchError捕獲異步異常
Future.delayed(Duration(seconds: 1))
    .then((e) => throw StateError('This is a Dart exception in Future.'))
    .catchError((e)=>print(e));
    
//***注意,以下代碼無法捕獲異步異常***
try {
  Future.delayed(Duration(seconds: 1))
      .then((e) => throw StateError('This is a Dart exception in Future.'))
}
catch(e) {
  print("This line will never be executed. ");
}

需要注意的是,這兩種方式是不能混用的。可以看到,在上面的代碼中,我們是無法使用try-catch去捕獲一個(gè)異步調(diào)用所拋出的異常的。

同步的try-catch和異步的catchError,為我們提供了直接捕獲特定異常的能力,而如果我們想集中管理代碼中的所有異常,F(xiàn)lutter也提供了Zone.runZoned方法。

我們可以給代碼執(zhí)行對象指定一個(gè)Zone,在Dart中,Zone表示一個(gè)代碼執(zhí)行的環(huán)境范圍,其概念類似沙盒,不同沙盒之間是互相隔離的。如果我們想要觀察沙盒中代碼執(zhí)行出現(xiàn)的異常,沙盒提供了onError回調(diào)函數(shù),攔截那些在代碼執(zhí)行對象中的未捕獲異常。

在下面的代碼中,我們將可能拋出異常的語句放置在了Zone里。可以看到,在沒有使用try-catch和catchError的情況下,無論是同步異常還是異步異常,都可以通過Zone直接捕獲到:

runZoned(() {
  //同步拋出異常
  throw StateError('This is a Dart exception.');
}, onError: (dynamic e, StackTrace stack) {
  print('Sync error caught by zone');
});

runZoned(() {
  //異步拋出異常
  Future.delayed(Duration(seconds: 1))
      .then((e) => throw StateError('This is a Dart exception in Future.'));
}, onError: (dynamic e, StackTrace stack) {
  print('Async error aught by zone');
});

因此,如果我們想要集中捕獲Flutter應(yīng)用中的未處理異常,可以把main函數(shù)中的runApp語句也放置在Zone中。這樣在檢測到代碼中運(yùn)行異常時(shí),我們就能根據(jù)獲取到的異常上下文信息,進(jìn)行統(tǒng)一處理了:

runZoned<Future<Null>>(() async {
  runApp(MyApp());
}, onError: (error, stackTrace) async {
 //Do sth for error
});

Framework異常的捕獲方式

Framework異常,就是Flutter框架引發(fā)的異常,通常是由應(yīng)用代碼觸發(fā)了Flutter框架底層的異常判斷引起的。比如,當(dāng)布局不合規(guī)范時(shí),F(xiàn)lutter就會(huì)自動(dòng)彈出一個(gè)觸目驚心的紅色錯(cuò)誤界面,如下所示:


1699431797925.jpg

這其實(shí)是因?yàn)椋現(xiàn)lutter框架在調(diào)用build方法構(gòu)建頁面時(shí)進(jìn)行了try-catch 的處理,并提供了一個(gè)ErrorWidget,用于在出現(xiàn)異常時(shí)進(jìn)行信息提示:

@override
void performRebuild() {
  Widget built;
  try {
    //創(chuàng)建頁面
    built = build();
  } catch (e, stack) {
    //使用ErrorWidget創(chuàng)建頁面
    built = ErrorWidget.builder(_debugReportException(ErrorDescription("building $this"), e, stack));
    ...
  } 
  ...
}

這個(gè)頁面反饋的信息比較豐富,適合開發(fā)期定位問題。但如果讓用戶看到這樣一個(gè)頁面,就很糟糕了。因此,我們通常會(huì)重寫ErrorWidget.builder方法,將這樣的錯(cuò)誤提示頁面替換成一個(gè)更加友好的頁面。

下面的代碼演示了自定義錯(cuò)誤頁面的具體方法。在這個(gè)例子中,我們直接返回了一個(gè)居中的Text控件

ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails){
  return Scaffold(
    body: Center(
      child: Text("Custom Error Widget"),
    )
  );
};

比起之前觸目驚心的紅色錯(cuò)誤頁面,白色主題的自定義頁面看起來稍微友好些了。需要注意的是,ErrorWidget.builder方法提供了一個(gè)參數(shù)details用于表示當(dāng)前的錯(cuò)誤上下文,為避免用戶直接看到錯(cuò)誤信息,這里我們并沒有將它展示到界面上。但是,我們不能丟棄掉這樣的異常信息,需要提供統(tǒng)一的異常處理機(jī)制,用于后續(xù)分析異常原因。

為了集中處理框架異常,F(xiàn)lutter提供了FlutterError類,這個(gè)類的onError屬性會(huì)在接收到框架異常時(shí)執(zhí)行相應(yīng)的回調(diào)。因此,要實(shí)現(xiàn)自定義捕獲邏輯,我們只要為它提供一個(gè)自定義的錯(cuò)誤處理回調(diào)即可。

在下面的代碼中,我們使用Zone提供的handleUncaughtError語句,將Flutter框架的異常統(tǒng)一轉(zhuǎn)發(fā)到當(dāng)前的Zone中,這樣我們就可以統(tǒng)一使用Zone去處理應(yīng)用內(nèi)的所有異常了:

FlutterError.onError = (FlutterErrorDetails details) async {
  //轉(zhuǎn)發(fā)至Zone中
  Zone.current.handleUncaughtError(details.exception, details.stack);
};

runZoned<Future<Null>>(() async {
  runApp(MyApp());
}, onError: (error, stackTrace) async {
 //Do sth for error
});

異常上報(bào)

到目前為止,我們已經(jīng)捕獲到了應(yīng)用中所有的未處理異常。但如果只是把這些異常在控制臺中打印出來還是沒辦法解決問題,我們還需要把它們上報(bào)到開發(fā)者能看到的地方,用于后續(xù)分析定位并解決問題。

關(guān)于開發(fā)者數(shù)據(jù)上報(bào),目前市面上有很多優(yōu)秀的第三方SDK服務(wù)廠商,比如友盟、Bugly,以及開源的Sentry等,而它們提供的功能和接入流程都是類似的??梢灾v異常日志上報(bào)給第三方sdk廠商。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 無論我們的應(yīng)用寫得多么完美、測試得多么全面,總是無法完全避免線上的異常問題。 這些異常,可能是因?yàn)椴怀浞值臋C(jī)型適配...
    半心_忬閱讀 4,529評論 3 11
  • Flutter 異常 Flutter 異常指的是,F(xiàn)lutter 程序中 Dart 代碼運(yùn)行時(shí)意外發(fā)生的錯(cuò)誤事件。...
    KB_MORE閱讀 2,622評論 0 5
  • 前提:Flutter異常指的是Flutter程序Dart代碼運(yùn)行時(shí)意外發(fā)生的錯(cuò)誤事件。我們可以通過try-catc...
    summer_maimaiti閱讀 702評論 0 0
  • Flutter 框架異常捕獲 Flutter 框架為我們在很多關(guān)鍵的方法進(jìn)行了異常捕獲。當(dāng)我們布局發(fā)生越界或不合規(guī)...
    愿天深海閱讀 644評論 0 2
  • 一、Flutter異常與Crash Flutter異常指的是Flutter程序在運(yùn)行時(shí)所拋出的異常分為: Dart...
    AlanGe閱讀 2,987評論 0 3

友情鏈接更多精彩內(nèi)容