Flutter捕获所有未处理的异常

时间:2019-09-10 23:54:07

标签: exception flutter dart

我正在尝试在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");
            },
          ),
        ),
      ),
    );
  }
}

4 个答案:

答案 0 :(得分:4)

您好 @james Allen ,我认为所有未处理的错误都可以全局捕获,并且无论模式如何,都可以在控制台中处理或打印。在您的示例中,我认为您在设置WidgetsFlutterBinding.ensureInitialized()之前错过了添加此行flutterError.onError的过程,因此它和您一样工作。

要处理抖动中的unhandled exceptions,我们可以从这些安全总结中获得帮助,以捕获那些异常,如下所列

  • 区域(以捕获所有unhandled-asynchronous-errors
  • FlutterError.onError(捕获所有unhandled-flutter-framework-errors

ZONE:

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");
  });
 }

FlutterError.onError:

从官方的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()

注意

  1. 闪烁的红色屏幕死机错误也会在flutterError.onError捕获程序下捕获。
  2. 在默认情况下,在生产模式下,在开发模式下,颤振红色屏幕将显示为红色,与颤振文档中的屏幕一样,纯BG。
  3. 根据我们的创造力可以自定义颤动屏死机。
  4. Flutter不会杀死应用程序,即使这些助手没有处理异常也是如此。
  5. 一个奖金-这些也是pub.dev中名为catcher的库,您可以查看一下错误捕获。

结合这两个来自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()}");
});