Flutter 捕获所有未处理的异常

Jam*_*len 29 exception dart flutter

我试图在 Flutter 应用程序中捕获所有未处理的异常,以便将其发送给崩溃报告者。Flutter 文档中关于如何执行此操作的说明。我遵循了这些,并在我的应用程序中添加了两段代码以捕获异常:

通过包装runApp来捕捉 Dart 错误runZoned

runZoned<Future<void>>(
  () async {
    runApp(MyApp());
  },
  onError: (dynamic error, StackTrace stackTrace) {
    print("=================== CAUGHT DART ERROR");
    // Send report
  },
);
Run Code Online (Sandbox Code Playgroud)

通过设置捕捉颤振错误FlutterError.onError

FlutterError.onError = (FlutterErrorDetails details) {
  print("=================== CAUGHT FLUTTER ERROR");
  // Send report
};
Run Code Online (Sandbox Code Playgroud)

但是,当我在运行时通过从按钮抛出异常进行测试时:

throw Exception("Just testing");
Run Code Online (Sandbox Code Playgroud)

控制台中出现异常:

????????? 异常捕获手势???????????????????????????????????????????????? ????????????????????? 处理手势时抛出了以下 _Exception: Exception: Just testing 当抛出异常时,这是堆栈:

... 等等

但是我看不到我的打印语句的迹象(CAUGHT DART ERROR 或 CAUGHT FLUTTER ERROR),并且在这些行上设置断点似乎永远不会命中,所以我认为我的异常处理代码没有捕捉到它。我错过了什么吗?

这是一个最小的可重现示例(单击按钮,该按钮会引发异常,但未按预期捕获):

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");
            },
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*len 37

好吧,我想通了是怎么回事。查看了一些相关的 Flutter 问题:

flutter 工具在捕获异常方面过于激进

使热模式在捕捉错误方面不那么激进

附加调试器时中断“未处理的”异常

看起来在调试模式下,flutter 框架捕获了很多异常,打印到控制台(有时在 UI 本身中以红色和黄色显示),但不会重新抛出 - 所以它们被有效地吞下,并且有您自己的代码无法捕获它们。但是,当您在发布模式下部署时,这不会发生。因此,我的最小可重现示例在以发布模式构建时确实会捕获异常。


Sar*_*aja 16

注意:使用 runZonedGuarded 更新了 onError deprecated 警告的示例代码

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

为了处理unhandled exceptions颤振,我们从这些安全包装中获得帮助以捕获这些异常,如下所列

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

区域:

zone 不属于 flutter 框架,它来自 dart 本身。在 dart 文档中,它指出..

区域保护您的应用程序不会因异步代码引发的未捕获异常而退出

参考链接https : //dart.dev/articles/archive/zones#handling-asynchronous-errors

因此,通过将我们的应用程序包装在 zone 内到我们的 flutter 应用程序,有助于捕获其简单代码下方的所有未处理的异步错误。

示例

void main() {
  runZonedGuarded(() async {
    runApp(MyApp()); // starting point of app
   },(error, stackTrace) {
      print("Error FROM OUT_SIDE FRAMEWORK ");
      print("--------------------------------");
      print("Error :  $error");
      print("StackTrace :  $stackTrace");
  });
 }
Run Code Online (Sandbox Code Playgroud)

FlutterError.onError :

来自官方颤振文档,它说,

Flutter 框架会捕获在框架本身触发的回调期间发生的错误,包括在构建、布局和绘制期间。

所有这些错误都被路由到 FlutterError.onError 处理程序。默认情况下,这会调用 FlutterError.dumpErrorToConsole,

参考链接https : //flutter.dev/docs/testing/errors

所以通过使用flutterError.onError我们可以捕获所有与颤振框架相关的错误,下面是它的简单示例..

例子:

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
 }
Run Code Online (Sandbox Code Playgroud)

WidgetsFlutterBinding.ensureInitialized()在设置 flutter 框架的错误捕获助手之前,不要忘记先添加这一行。

注意

  1. flutter 红屏死机错误也会在flutterError.onError catcher下捕获。
  2. 默认情况下,在生产中,Flutter 红屏将在开发模式下可见,它与 Flutter 文档中的 BG 一样。
  3. Flutter screen to death 可以根据我们的创造力进行定制。
  4. Flutter 不会杀死应用程序,即使这些帮助程序不处理异常。
  5. 奖励之一 - 这些也是pub.dev 中称为catcher的库,您可以查看错误捕获。

结合 dart 和 flutter 框架中的这两个助手,我们可以全局捕获所有未处理的错误,这些都是我在 flutter 中被分配执行全局异常处理任务时从 Web 文档中了解到的,如果有任何错误,请随时纠正我。


Duy*_*ran 10

确保您像这样使用WidgetsFlutterBinding.ensureInitialized()

runZonedGuarded(() {
  WidgetsFlutterBinding.ensureInitialized(); //<= the key is here
  FlutterError.onError = (FlutterErrorDetails errorDetails) {
    Utilities.log("Will log here ${errorDetails.exception.toString()}");
  };
  runApp(app);
}, (error, stackTrace) {
  Utilities.log("Others catching ${error.toString()}");
});
Run Code Online (Sandbox Code Playgroud)