Flutter異常收集主要指的是Dart端的異常收集,涉及到原生異常的收集,這里沒有涉及。
Flutter異常收集包括兩點(diǎn),系統(tǒng)已經(jīng)捕獲的異常的收集和系統(tǒng)沒有捕獲的異常的收集。
1,系統(tǒng)已經(jīng)捕獲的異常收集
Flutter 在很多關(guān)鍵的方法中進(jìn)行了異常捕獲,比如在布局發(fā)生越界或者錯(cuò)誤時(shí),F(xiàn)lutter會(huì)自動(dòng)彈出錯(cuò)誤界面。因?yàn)镕lutter在執(zhí)行build方法時(shí),進(jìn)行了異常捕獲。
如果我們想自己上報(bào)異常,只需要給flutter.onError賦值,如下:
voidmain(){
????FlutterError.onError=(FlutterErrorDetails details){
????????reportError(details);
????};
????...
}
2,其他的異常和日志收集
Flutter中還有一些沒有為我們捕獲的異常,比如空對(duì)象方法異常,F(xiàn)uture中的異常,等。Dart中異常分為兩類,同步異常和異步異常。同步可以通過try/catch捕獲,異步異常比較麻煩。如下代碼,無法捕捉下面的異常(當(dāng)然如果前面加個(gè)await應(yīng)該是可以的):
try{
????Future.delayed(Duration(seconds:1)).then((e)=>Future.error("xxx"));
}catch(e){
????print(e);
}
我們可以通過runZoned(...) 方法捕捉異常。runZoned方法可以給執(zhí)行的對(duì)象,分配個(gè)執(zhí)行環(huán)境。將Zone比做一個(gè)代碼執(zhí)行沙箱,不同的沙箱之間是隔離的。沙箱可以捕獲,攔截或者修改一些代碼行為,如Zone中可以捕獲日志輸出,Timer 創(chuàng)建,微任務(wù)調(diào)度等行為。同時(shí)Zone也可以捕獲所有未處理的異常。
下面是runZoned的方法定義:
R runZoned<R>(Rbody(),{Map zoneValues,ZoneSpecification zoneSpecification,FunctiononError,})
body:執(zhí)行的代碼
zoneValues:zone的私有數(shù)據(jù),可以通過zone[key]獲取,可以理解為每個(gè)沙箱的私有數(shù)據(jù)。
zoneSpecification:Zone的一些配置,可以自定義一些代碼行為,比如攔截日志輸出等。
main() {
? ? runZoned(
? ? ? ? ()=>runApp(MyApp()),
? ? ? ? ? ? zoneSpecification: ZoneSpecification(
? ? ? ? ? ? ? ? print:(Zone self,ZoneDelegate parent,Zone zone,String line){parent.print(zone,"Intercepted: ????????????????$line");}),
????????????)
????????);
}
onError: 發(fā)生為捕獲異常時(shí),執(zhí)行的回調(diào)。
runZoned((){runApp(MyApp());},onError:(Object obj,StackTrace stack){vardetails=makeDetails(obj,stack);reportError(details);});
總結(jié):最終的異常捕獲和上報(bào)代碼大致如下:
void collectLog(String line){
...//收集日志
}
void reportErrorAndLog(FlutterErrorDetails details){
...//上報(bào)錯(cuò)誤和日志邏輯
}
FlutterErrorDetailsmakeDetails(Object obj,StackTrace stack){
...// 構(gòu)建錯(cuò)誤信息
}
voidmain(){
????FlutterError.onError(FlutterErrorDetailsdetails{
????????reportErrorAndLog(details);
????};
????runZoned(
????????()=>runApp(MyApp()),
????????zoneSpecification:ZoneSpecification(
????????????print:(Zone self,ZoneDelegate parent,Zone zone,String line){
????????????????collectLog(line);// 收集日志}
????????,),
????????onError:(Object obj,StackTrace stack){
????????????vardetails=makeDetails(obj,stack);
????????????reportErrorAndLog(details);
????????},
????);
}