Flutter異常捕獲runZoned

Flutter異常捕獲
Dart中可以通過try/catch/finally來捕獲代碼塊異常顷歌,這個和其它變成語言類似气忠,邻储,如果讀者不清楚,可以查看Dart語言文檔旧噪,不在贅述吨娜,下面我們看看Flutter中的異常捕獲。

Flutter框架異常捕獲

Flutter 框架為我們在很多關鍵的方法進行了異常捕獲淘钟。這里舉一個例子宦赠,當我們布局發(fā)生越界或不和規(guī)范時,F(xiàn)lutter就會自動彈出一個錯誤界面米母,這是因為Flutter已經(jīng)在執(zhí)行build方法時添加了異常捕獲勾扭,最終的源碼如下:

@override
void performRebuild() {
 ...
  try {
    //執(zhí)行build方法  
    built = build();
  } catch (e, stack) {
    // 有異常時則彈出錯誤提示  
    built = ErrorWidget.builder(_debugReportException('building $this', e, stack));
  } 
  ...
}      

可以看到,在發(fā)生異常時铁瞒,F(xiàn)lutter默認的處理方式時彈一個ErrorWidget妙色,但如果我們想自己捕獲異常并上報到報警平臺的話應該怎么做?我們進入_debugReportException()方法看看:

FlutterErrorDetails _debugReportException(
  String context,
  dynamic exception,
  StackTrace stack, {
  InformationCollector informationCollector
}) {
  //構(gòu)建錯誤詳情對象  
  final FlutterErrorDetails details = FlutterErrorDetails(
    exception: exception,
    stack: stack,
    library: 'widgets library',
    context: context,
    informationCollector: informationCollector,
  );
  //報告錯誤 
  FlutterError.reportError(details);
  return details;
}

我們發(fā)現(xiàn)慧耍,錯誤是通過FlutterError.reportError方法上報的身辨,繼續(xù)跟蹤:

static void reportError(FlutterErrorDetails details) {
  ...
  if (onError != null)
    onError(details); //調(diào)用了onError回調(diào)
}

我們發(fā)現(xiàn)onError是FlutterError的一個靜態(tài)屬性,它有一個默認的處理方法 dumpErrorToConsole芍碧,到這里就清晰了煌珊,如果我們想自己上報異常,只需要提供一個自定義的錯誤處理回調(diào)即可泌豆,如:

void main() {
  FlutterError.onError = (FlutterErrorDetails details) {
    reportError(details);
  };
 ...
}

這樣我們就可以處理那些Flutter為我們捕獲的異常了定庵,接下來我們看看如何捕獲其它異常。

其它異常捕獲與日志收集

在Flutter中,還有一些Flutter沒有為我們捕獲的異常洗贰,如調(diào)用空對象方法異常、Future中的異常陨倡。在Dart中敛滋,異常分兩類:同步異常和異步異常,同步異承烁铮可以通過try/catch捕獲绎晃,而異步異常則比較麻煩,如下面的代碼是捕獲不了Future的異常的:

try{
    Future.delayed(Duration(seconds: 1)).then((e) => Future.error("xxx"));
}catch (e){
    print(e)
}

Dart中有一個runZoned(...) 方法杂曲,可以給執(zhí)行對象指定一個Zone庶艾。Zone表示一個代碼執(zhí)行的環(huán)境范圍,為了方便理解擎勘,讀者可以將Zone類比為一個代碼執(zhí)行沙箱咱揍,不同沙箱的之間是隔離的,沙箱可以捕獲棚饵、攔截或修改一些代碼行為煤裙,如Zone中可以捕獲日志輸出、Timer創(chuàng)建噪漾、微任務調(diào)度的行為硼砰,同時Zone也可以捕獲所有未處理的異常。下面我們看看runZoned(...)方法定義:

R runZoned<R>(R body(), {
    Map zoneValues, 
    ZoneSpecification zoneSpecification,
    Function onError,
}) 

zoneValues: Zone 的私有數(shù)據(jù)欣硼,可以通過實例zone[key]獲取题翰,可以理解為每個“沙箱”的私有數(shù)據(jù)。

zoneSpecification:Zone的一些配置诈胜,可以自定義一些代碼行為豹障,比如攔截日志輸出行為等,舉個例子:

下面面是攔截應用中所有調(diào)用print輸出日志的行為耘斩。

main() {
runZoned(() => runApp(MyApp()), zoneSpecification: new ZoneSpecification(
    print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
      parent.print(zone, "Intercepted: $line");
    }),
);
}

這樣一來沼填,我們APP中所有調(diào)用print方法輸出日志的行為都會被攔截,通過這種方式括授,我們也可以在應用中記錄日志坞笙,等到應用觸發(fā)未捕獲的異常時,將異常信息和日志統(tǒng)一上報荚虚。ZoneSpecification還可以自定義一些其他行為薛夜,讀者可以查看API文檔。

onError:Zone中未捕獲異常處理回調(diào)版述,如果開發(fā)者提供了onError回調(diào)或者通過ZoneSpecification.handleUncaughtError指定了錯誤處理回調(diào)梯澜,那么這個zone將會變成一個error-zone,該error-zone中發(fā)生未捕獲異常(無論同步還是異步)時都會調(diào)用開發(fā)者提供的回調(diào)渴析,如:

runZoned(() {
  runApp(MyApp());
}, onError: (Object obj, StackTrace stack) {
  var details=makeDetails(obj,stack);
  reportError(details);
});

這樣一來晚伙,結(jié)合上面的FlutterError.onError我們就可以捕獲我們Flutter應用中全部錯誤了吮龄!需要注意的是,error-zone內(nèi)部發(fā)生的錯誤是不會跨越當前error-zone的邊界的咆疗,如果想跨越error-zone邊界去捕獲異常漓帚,可以通過共同的“源”zone來捕獲,如:

var future = new Future.value(499);
runZoned(() {
var future2 = future.then((_) { throw "error in first error-zone"; });
runZoned(() {
    var future3 = future2.catchError((e) { print("Never reached!"); });
}, onError: (e) { print("unused error handler"); });
}, onError: (e) { print("catches error of first error-zone."); }
);

總結(jié)

我們最終的異常捕獲和上報代碼如下:

void collectLog(String line){
    ... //收集日志
}
void reportErrorAndLog(FlutterErrorDetails details){
    ... //上報錯誤和日志邏輯
}

FlutterErrorDetails makeDetails(Object obj, StackTrace stack){
    ...// 構(gòu)建錯誤信息
}

void main() {
  FlutterError.onError = (FlutterErrorDetails details) {
    reportErrorAndLog(details);
  };
  runZoned(
    () => runApp(MyApp()),
    zoneSpecification: ZoneSpecification(
      print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
        collectLog(line); //手機日志
      },
    ),
    onError: (Object obj, StackTrace stack) {
      var details = makeDetails(obj, stack);
      reportErrorAndLog(details);
    },
  );
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末午磁,一起剝皮案震驚了整個濱河市尝抖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌迅皇,老刑警劉巖昧辽,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異登颓,居然都是意外死亡搅荞,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門挺据,熙熙樓的掌柜王于貴愁眉苦臉地迎上來取具,“玉大人,你說我怎么就攤上這事扁耐∠炯欤” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵婉称,是天一觀的道長块仆。 經(jīng)常有香客問我,道長王暗,這世上最難降的妖魔是什么悔据? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮俗壹,結(jié)果婚禮上科汗,老公的妹妹穿的比我還像新娘。我一直安慰自己绷雏,他們只是感情好头滔,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涎显,像睡著了一般坤检。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上期吓,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天早歇,我揣著相機與錄音,去河邊找鬼。 笑死箭跳,一個胖子當著我的面吹牛晨另,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谱姓,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼拯刁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了逝段?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤割捅,失蹤者是張志新(化名)和其女友劉穎奶躯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亿驾,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡嘹黔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了莫瞬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儡蔓。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疼邀,靈堂內(nèi)的尸體忽然破棺而出喂江,到底是詐尸還是另有隱情,我是刑警寧澤旁振,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布获询,位于F島的核電站,受9級特大地震影響拐袜,放射性物質(zhì)發(fā)生泄漏吉嚣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一蹬铺、第九天 我趴在偏房一處隱蔽的房頂上張望尝哆。 院中可真熱鬧,春花似錦甜攀、人聲如沸秋泄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽印衔。三九已至,卻和暖如春姥敛,著一層夾襖步出監(jiān)牢的瞬間奸焙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留与帆,地道東北人了赌。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像玄糟,于是被迫代替她去往敵國和親勿她。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容