1.Flutter 异常捕获机制
Dart 中可以通过 try/catch/on /finally 来捕获代码块异常,这个和其它变成语类似
try:执行的 代码,其中有可能异常,一旦发生异常,则立即跳转到catch 执行,否则catch里面的内容不执行
on: 当你需要指定异常类型的时候使用 on
catch:除非try有异常,否则不执行,使用rethrow
关键词让异常传递下去
finally:不管什么情况都会执行,不过 try ,catch 里面使用了return
void exceptionTest(){
try {
int result = 12 ~/ 0;
print("result is $result");
}on IntegerDivisionByZeroException {
print("Cannot deivide by zero");
}
}
void exceptionTest2(){
try {
int result = 12 ~/ 0;
print("result is $result");
}catch (e,s) {
print("The exception throw is $e");
print("STACK TRACE \n $S");
}
}
//case4
void exceptionTest2(){
try {
int result = 12 ~/ 0;
print("result is $result");
}catch (e,s) {
print("The exception throw is $e");
print("STACK TRACE \n $S");
}
} finally {
print("不管有没有异常都会执行");
}
常见异常
- DeferredLoadException 延迟库无法加载
- FormatException 数据类型转换异常,或解析异常
- IntegerDivisionByZeroException 数字除以零
- IOException IO流异常
- NullPoingtException 空指针异常
自己实现简单的异常捕获
在Dart高效编程中一般建议继承Error
或者 Exception
类作为子类实现错误或者异常的抛出。
main(List args) {
try {
depositMoney(200);
}catch (e) {
print("error is $e");
}
}
class DepositException implements Exception {
String errorMessage() {
return "金额不能少于0";
}
}
void depositMoney(int amount) {
if (amount <= 0) {
throw new DepositException();
}
}
2. Flutter框架异常捕获,这块不拓展,留给以后
Flutter 框架为我们在很多关键的方法进行了异常捕获。例如:当我们布局发生越界或不合规范时,Flutter会自动弹出一个错误界面,这是因为Flutter在执行build方法时添加了异常捕获,下面是源码如下:
// 系统里面的源码
@override
void performRebuild() {
if (!kReleaseMode && debugProfileBuildsEnabled)
Timeline.startSync('${widget.runtimeType}', arguments: timelineWhitelistArguments);
assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true));
Widget built;
try {
built = build();
debugWidgetBuilderValue(widget, built);
} catch (e, stack) {
built = ErrorWidget.builder(
_debugReportException(
ErrorDescription('building $this'),
e,
stack,
informationCollector: () sync* {
yield DiagnosticsDebugCreator(DebugCreator(this));
},
),
);
} finally {
// We delay marking the element as clean until after calling build() so
// that attempts to markNeedsBuild() during build() will be ignored.
_dirty = false;
assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(false));
}
try {
_child = updateChild(_child, built, slot);
assert(_child != null);
} catch (e, stack) {
built = ErrorWidget.builder(
_debugReportException(
ErrorDescription('building $this'),
e,
stack,
informationCollector: () sync* {
yield DiagnosticsDebugCreator(DebugCreator(this));
},
),
);
_child = updateChild(null, built, slot);
}
if (!kReleaseMode && debugProfileBuildsEnabled)
Timeline.finishSync();
}
_debugReportException
方法中最终通过 FlutterError.reportError
将错误信息进行上报:
FlutterErrorDetails _debugReportException(
String context,
dynamic exception,
StackTrace stack, {
InformationCollector informationCollector
}) {
//构建错误详情对象
final FlutterErrorDetails details = FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'widgets library',
context: context,
informationCollector: informationCollector,
);
//报告错误
FlutterError.reportError(details);
return details;
}
reportError
方法中最终通过 onError
属性处理错误信息(实际上 onError
有默认实现 dumpErrorToConsole
)。我们可以通过重写 onError
属性拦截上报信息(reportError
方法):
void main() {
FlutterError.onError = (FlutterErrorDetails details) {
reportError(details);
};
runApp(FilePathProviderApplication());
}
如果我们需要自定义错误页面,则需要重写 ErrorWidget.builder
:
void main() {
ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails) {
print(flutterErrorDetails.toString());
return Center(
child: Text("Flutter 崩溃了"),
);
};
runApp(FilePathProviderApplication());
}
Flutter 端异常捕获实践
对于 Flutter
端的异常信息,除了能够使用 try-catch
捕获的同步异常之外,大多数情况下异常信息集中在 Flutter
端的页面渲染方面,所以我们需要重写 FlutterError.onError
用于处理框架层自动添加的异常捕获:
const bool inProduction = const bool.fromEnvironment("dart.vm.product");
FlutterError.onError = (FlutterErrorDetails details) async {
if (inProduction) {
Zone.current.handleUncaughtError(details.exception, details.stack);
} else {
FlutterError.dumpErrorToConsole(details);
}
};
在非生产环境下,异常信息通过 FlutterError.dumpErrorToConsole(details)
交由控制台进行输出,生产环境则通过 Zone.current.handleUncaughtError(details.exception, details.stack)
将异常信息交付给 Flutter
层的全局异常捕获进行处理。
然后,我们再为整个应用程序的 Flutter
层添加全局异常捕获
runZoned>(() async {
runApp(new HomeApp());
}, onError: (error, stackTrace) async {
await _reportError(error, stackTrace);
});