Flutter & Dart 中的异常处理
哪些场景下需要错误处理介入
同步代码
同步代码中,try-catch-finally
是最常用的错误处理方式
rethrow
可以将错误信息重新上抛
try {
print('Allocate something 3');
throw 'Other error occurred';
} on IntegerDivisionByZeroException {
print('Cant divide to zero');
} on FormatException catch (e) {
print('Format exceptions: $e');
} catch (e, s) {
print('Unknown exceptions: $e, with stack: \n$s');
rethrow;
} finally {
print('Clean-up something 3');
}
异步代码
异步代码的错误处理也是用try-catch-finally
,但要注意写法
下面是错误的例子
try {
Future.delayed(Duration(seconds: 1), () {
final _ = 100 ~/ 0;
});
print('Everything is fine!');
} on IntegerDivisionByZeroException {
print('Cant divide to zero');
} finally {
print('Clean-up done');
}
为了能捕获到Futrue的错误可以有以下处理方式:
- 加await
try {
await Future.delayed(Duration(seconds: 1), () {
final _ = 100 ~/ 0;
});
print('Everything is fine!');
} on IntegerDivisionByZeroException {
print('Cant divide to zero');
} finally {
print('Clean-up done');
}
2.catchError & whenComplete结构
catchError是捕获上方代码的异常,是catch的模拟,如果想模拟finally,则可以在catchError后加whenComplete,
另外可以使用test来模拟on Exeption,判断异常的类型
await Future.delayed(Duration(seconds: 1), () {
print('Its fie so far');
}).then((value) {
print('Then started');
throw 'random exception';
}).catchError((error) {
print('Cant divide to zero');
}, test: (e) => e is IntegerDivisionByZeroException).catchError((error) {
print('All other exceptions: $error');
}, test: (e) => true).whenComplete(() {
print('Clean-up done');
});
定时器
定时器使用Zones
和runZonedGuarded
处理异常,Zones
可以将timer,微任务,Future的回调包起来(黑盒的try-catch-finally),通过Zones对外的方法实现异常处理,注意,Zones里面捕获的异常是不会抛到上层,已经被Flutter框架捕获的异常,不会被runZoneGuarded捕获
print('Current zone start in: ${Zone.current.toString()}');
runZonedGuarded(() {
print('Current zone inside runZoned: ${Zone.current.toString()} with name ${Zone.current['ZoneName']}');
Timer.run(() {
print('Timer runs.');
throw Exception('[Timer] Bad thing happens!');
});
runZonedGuarded(
() {
print('Current zone (1) inside runZoned: ${Zone.current.toString()} with name ${Zone.current['ZoneName']}');
Timer.run(() {
print('Timer 1 runs. ');
throw Exception('[Timer 1] Bad thing happens!');
});Flutter & Dart 中的异常处理
},
(e, s) {
print('Current zone (1) inside catch: ${Zone.current.toString()} with name ${Zone.current['ZoneName']}');
print('Exception handled (1) $e, \n$s');
},
zoneValues: {'ZoneName': 'Second zone'},
);
print('Everything is fine!');
}, (e, s) {
print('Current zone inside catch: ${Zone.current.toString()} with name ${Zone.current['ZoneName']}');
print('Exception handled $e, \n$s');
}, zoneValues: {'ZoneName': 'First zone'});
流操作
流操作也是用Zone来捕获异常
Flutter App全局整体
使用FlutterError.onError回调方法,可以将上述捕获的异常记录下来,使用FlutterError.onError回调之前,要先WidgetsFlutterBinding.ensureInitialized()