Flutter异常收集主要指的是Dart端的异常收集,涉及到原生异常的收集,这里没有涉及。
Flutter异常收集包括两点,系统已经捕获的异常的收集和系统没有捕获的异常的收集。
1,系统已经捕获的异常收集
Flutter 在很多关键的方法中进行了异常捕获,比如在布局发生越界或者错误时,Flutter会自动弹出错误界面。因为Flutter在执行build方法时,进行了异常捕获。
如果我们想自己上报异常,只需要给flutter.onError赋值,如下:
voidmain(){
FlutterError.onError=(FlutterErrorDetails details){
reportError(details);
};
...
}
2,其他的异常和日志收集
Flutter中还有一些没有为我们捕获的异常,比如空对象方法异常,Future中的异常,等。Dart中异常分为两类,同步异常和异步异常。同步可以通过try/catch捕获,异步异常比较麻烦。如下代码,无法捕捉下面的异常(当然如果前面加个await应该是可以的):
try{
Future.delayed(Duration(seconds:1)).then((e)=>Future.error("xxx"));
}catch(e){
print(e);
}
我们可以通过runZoned(...) 方法捕捉异常。runZoned方法可以给执行的对象,分配个执行环境。将Zone比做一个代码执行沙箱,不同的沙箱之间是隔离的。沙箱可以捕获,拦截或者修改一些代码行为,如Zone中可以捕获日志输出,Timer 创建,微任务调度等行为。同时Zone也可以捕获所有未处理的异常。
下面是runZoned的方法定义:
R runZoned<R>(Rbody(),{Map zoneValues,ZoneSpecification zoneSpecification,FunctiononError,})
body:执行的代码
zoneValues:zone的私有数据,可以通过zone[key]获取,可以理解为每个沙箱的私有数据。
zoneSpecification:Zone的一些配置,可以自定义一些代码行为,比如拦截日志输出等。
main() {
runZoned(
()=>runApp(MyApp()),
zoneSpecification: ZoneSpecification(
print:(Zone self,ZoneDelegate parent,Zone zone,String line){parent.print(zone,"Intercepted: $line");}),
)
);
}
onError: 发生为捕获异常时,执行的回调。
runZoned((){runApp(MyApp());},onError:(Object obj,StackTrace stack){vardetails=makeDetails(obj,stack);reportError(details);});
总结:最终的异常捕获和上报代码大致如下:
void collectLog(String line){
...//收集日志
}
void reportErrorAndLog(FlutterErrorDetails details){
...//上报错误和日志逻辑
}
FlutterErrorDetailsmakeDetails(Object obj,StackTrace stack){
...// 构建错误信息
}
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);
},
);
}