我正在尝试在Flutter应用程序中捕获所有未处理的异常,以便将其发送给崩溃报告器。有instructions on how to do this in the Flutter docs。我遵循了这些规则,并向我的应用程序添加了两位代码以捕获异常:
通过将runApp
包装在runZoned
中来捕获Dart错误:
runZoned<Future<void>>(
() async {
runApp(MyApp());
},
onError: (dynamic error, StackTrace stackTrace) {
print("=================== CAUGHT DART ERROR");
// Send report
},
);
通过设置FlutterError.onError
捕获抖动错误:
FlutterError.onError = (FlutterErrorDetails details) {
print("=================== CAUGHT FLUTTER ERROR");
// Send report
};
但是,当我在运行时通过从按钮引发异常来对此进行测试时:
throw Exception("Just testing");
例外出现在控制台中:
════════手势捕获异常 ══════════════════════════════════════════════════ ═════════════ 处理手势时引发了以下_Exception异常: 只是测试例外是 抛出,这是堆栈:
...等等
但是我看不到我的打印语句的迹象(提示飞镖错误或提示颤音错误),并且在这些行上设置断点似乎从未命中,因此我认为我的异常处理代码无法捕获它。我想念什么吗?
这是一个最小的可重现示例(单击按钮会引发异常,但未按预期捕获):
import 'dart:async';
import 'package:flutter/material.dart';
void main() =>
runZoned<Future<void>>(
() async {
runApp(MyApp());
},
onError: (dynamic error, StackTrace stackTrace) {
print("=================== CAUGHT DART ERROR");
// Send report
// NEVER REACHES HERE - WHY?
},
);
class MyApp extends StatefulWidget {
// This widget is the root of your application.
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
// This captures errors reported by the FLUTTER framework.
FlutterError.onError = (FlutterErrorDetails details) {
print("=================== CAUGHT FLUTTER ERROR");
// Send report
// NEVER REACHES HERE - WHY?
};
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: RaisedButton(
child: Text("Throw exception"),
onPressed: () {
throw Exception("This is a test exception");
},
),
),
),
);
}
}
答案 0 :(得分:4)
您好 @james Allen ,我认为所有未处理的错误都可以全局捕获,并且无论模式如何,都可以在控制台中处理或打印。在您的示例中,我认为您在设置WidgetsFlutterBinding.ensureInitialized()
之前错过了添加此行flutterError.onError
的过程,因此它和您一样工作。
要处理抖动中的unhandled exceptions
,我们可以从这些安全总结中获得帮助,以捕获那些异常,如下所列
unhandled-asynchronous-errors
)unhandled-flutter-framework-errors
)zone不属于Flutter框架,它来自Dart本身。在dart文档中说明了这一点。
区域可保护您的应用程序免于因未捕获的异常而退出 异步代码抛出
参考链接:https://dart.dev/articles/archive/zones#handling-asynchronous-errors
因此,通过将我们的应用程序内部区域包装到我们的flutter应用程序中,有助于在其简单代码下捕获所有未处理的异步错误。
示例:
void main() {
runZoned(() async {
runApp(MyApp()); // starting point of app
}, onError: (error, stackTrace) {
print("Error FROM OUT_SIDE FRAMEWORK ");
print("--------------------------------");
print("Error : $error");
print("StackTrace : $stackTrace");
});
}
从官方的flutter文档中说,
Flutter框架捕获回调期间发生的错误 由框架本身触发,包括在构建,布局和 油漆。
所有这些错误都路由到FlutterError.onError处理程序。通过 默认情况下,它调用FlutterError.dumpErrorToConsole,
参考链接:https://flutter.dev/docs/testing/errors
因此,通过使用flutterError.onError
,我们可以在其简单示例下面捕获所有与Flutter框架相关的错误。
示例:
void main() {
WidgetsFlutterBinding.ensureInitialized(); //imp line need to be added first
FlutterError.onError = (FlutterErrorDetails details) {
//this line prints the default flutter gesture caught exception in console
//FlutterError.dumpErrorToConsole(details);
print("Error From INSIDE FRAME_WORK");
print("----------------------");
print("Error : ${details.exception}");
print("StackTrace : ${details.stack}");
};
runApp(MyApp()); // starting point of app
}
在设置flutter框架的错误捕获帮助程序之前,请不要忘记首先添加此行WidgetsFlutterBinding.ensureInitialized()
。
注意:
结合这两个来自dart&flutter框架的帮助程序,我们可以全局捕获所有未处理的错误,当我被分配为flutter中的全局异常处理任务时,这些都是我从Web文档中了解的,请随时纠正我任何错误。
答案 1 :(得分:1)
好吧,我知道发生了什么事。看了一些相关的Flutter问题:
flutter tool is too aggressive about catching exceptions
Make hot mode a little less aggressive about catching errors
Break on "unhandled" exceptions when a debugger is attached
在调试模式下,flutter框架似乎捕获了许多异常,打印到控制台(有时在UI本身中以红色和黄色显示),但没有重新抛出-因此它们有效吞没了,您自己的代码无法捕获它们。但是,当您以发布模式进行部署时,这不会发生。因此,我的最小可重现示例在发布模式下构建时确实捕获了异常。
答案 2 :(得分:0)
因此,“ runZoned”和“ Flutter.onError”分别用于在dart和flutter框架中进行“错误”处理。但是在您的代码中,您抛出了“异常”。这不是由'run ..'或'..onErr'处理的。如果要在控制台中看到“ Just testing”,请如下修改throw语句-> throw“ Just testing”;并且您将在控制台日志中看到它。
答案 3 :(得分:0)
确保您像这样使用 WidgetsFlutterBinding.ensureInitialized()
runZonedGuarded(() {
WidgetsFlutterBinding.ensureInitialized();
FlutterError.onError = (FlutterErrorDetails errorDetails) {
Utilities.log("Will log here ${errorDetails.exception.toString()}");
};
runApp(app);
}, (error, stackTrace) {
Utilities.log("For other catch ${error.toString()}");
});