Flutter 全局异常的捕捉

Flutter异常指的是Flutter程序在运行时所抛出的异常分为:

  • Dart代码运行时发生的异常
  • Flutter框架异常
  • 原生代码运行时抛出的异常,如:Android 的Java和kotlin,iOS的OC和swift

做Flutter应用Dart代码占绝大多数,所以本文我们重点学习下Flutter中Dart和框架异常的捕获与收集。

Dart代码运行时发生的异常与Java、kotlin、OC等具有多线程模型的编程语言不同,Dart是一门单线程的编程语言,采用事件循环机制来运行任务,所以各个任务的运行状态是互相独立的。也即是说,当程序运行过程中出现异常时,即使没有像Java那样使用try-catch机制来捕获异常,Dart程序也不会退出,只会导致当前任务后续的代码不会被执行,而其它功能仍然可以继续使用。

异常捕获

根据异常代码的执行时序,Dart异常可以分为同步和异步异常两类。首先我们看同步异常的捕获方式:

同步异常的捕获方式:

//使用try-catch捕获同步异常
    try {
      throw StateError('There is a dart exception.');
    } catch (e) {
      print(e);
    }

异步异常的捕获有两种方式:

  • 一种是使用Future提供的catchError语句来进行捕获;
  • 另外一种是将异步转同步然后通过try-catch进行捕获;
  • //使用catchError捕获异步异常
        Future.delayed(Duration(seconds: 1))
            .then(
                (e) => throw StateError('This is first Dart exception in Future.'))
            .catchError((e) => print(e));
    
    //异步转同步
        try {
          await Future.delayed(Duration(seconds: 1)).then(
              (e) => throw StateError('This is second Dart exception in Future.'));
        } catch (e) {
          print(e);
        }

集中捕获异常

在Android中我们可以通过Thread.UncaughtExceptionHandler接口来集中收集异常,那么在Flutter中如何集中收集异常呢?

Flutter提供的Zone.runZonedGuarded()方法。在Dart语言中,Zone表示一个代码执行的环境范围,其概念类似沙盒,不同沙盒之间是互相隔离的。如果想要处理沙盒中代码执行出现的异常,可以使用沙盒提供的onError回调函数来拦截那些在代码执行过程中未捕获的异常:

 runZonedGuarded(() {
      throw StateError('runZonedGuarded:This is a Dart exception.');
    }, (e, s) => print(e));
    runZonedGuarded(() {
      Future.delayed(Duration(seconds: 1)).then((e) => throw StateError(
          'runZonedGuarded:sThis is a Dart exception in Future.'));
    }, (e, s) => print(e));

从上述代码中不难看出,无论是同步异常还是异步异常,都可以使用Zone直接捕获到。同时,如果需要集中捕获Flutter应用中未处理的异常,那么可以把main函数中的runApp语句也放置在Zone中,这样就可以在检测到代码运行异常时对捕获的异常信息进行统一处理:

runZonedGuarded<Future<Null>>(() async {
    runApp(BiliApp());
  }, (e, s) => print(e));

最终DEMO

void main() {
  AppCatchError().run(MineApp());
}

//全局异常的捕捉
class AppCatchError {
  run(Widget app) {
    ///Flutter 框架异常
    FlutterError.onError = (FlutterErrorDetails details) async {
      ///线上环境
      ///TODO
      if (kReleaseMode) {
        Zone.current.handleUncaughtError(details.exception, details.stack!);
      } else {
        //开发期间 print
        FlutterError.dumpErrorToConsole(details);
      }
    };

    runZonedGuarded(() {
      //受保护的代码块
      runApp(app);
    }, (error, stack) => catchError(error, stack));
  }

  ///对搜集的 异常进行处理  上报等等
  catchError(Object error, StackTrace stack) {
    print("AppCatchError>>>>>>>>>>: $kReleaseMode"); //是否是 Release版本
    print('AppCatchError message:$error,stack$stack');
  }
}

异常上报

捕获到异常后可以在上述_reportError方法中上报到服务端,像BAT等一线互联网大厂都有自己的Crash监控平台。如果公司没有自己的Crash平台,可以接入第三方的如:Buggly。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Flutter中,您可以使用以下方法定义全局变量: 1. 使用`final`或`const`关键字: 您可以在您的Dart文件中使用`final`或`const`关键字来定义全局变量。这些变量必须在声明时初始化,并且在整个应用程序中都是不可变的。 例如: ``` final String myGlobalVar = 'Hello World'; const int myGlobalNum = 42; ``` 2. 在`main.dart`文件中使用`static`关键字: 您可以在`main.dart`文件中使用`static`关键字来定义全局变量。这些变量可以在整个应用程序中访问,并且可以在运行时更改值。 例如: ``` void main() { MyApp.myGlobalVar = 'Hello World'; runApp(MyApp()); } class MyApp extends StatelessWidget { static String myGlobalVar; ... } ``` 3. 使用`Provider`或`GetX`等状态管理库: 您可以使用状态管理库(如`Provider`或`GetX`)来管理全局变量,并在整个应用程序中共享它们。 例如: ``` // Using Provider library void main() { runApp( ChangeNotifierProvider( create: (context) => MyGlobalVar(), child: MyApp(), ), ); } class MyGlobalVar extends ChangeNotifier { String myGlobalVar = 'Hello World'; void updateMyGlobalVar(String newValue) { myGlobalVar = newValue; notifyListeners(); } } class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { final myGlobalVar = Provider.of<MyGlobalVar>(context); return Text(myGlobalVar.myGlobalVar); } } // Using GetX library void main() => runApp(MyApp()); class MyGlobalVar extends GetxController { RxString myGlobalVar = 'Hello World'.obs; void updateMyGlobalVar(String newValue) { myGlobalVar.value = newValue; } } class MyWidget extends StatelessWidget { final MyGlobalVar myGlobalVar = Get.find(); @override Widget build(BuildContext context) { return Text(myGlobalVar.myGlobalVar.value); } } ``` 这些是定义全局变量的一些常见方法。根据您的应用程序需求和上下文选择合适的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值