• Flutter Dart回顾 —— 异常捕获、抛出


      一、Dart 异常捕获、抛出

      在Dart中,异常分两类:同步异常和异步异常

    1、同步异常:

    Dart中同步异常可以通过try/on/catch/finally来捕获代码块异常,可以通过throw 关键字用来明确地抛出异常。如下案例:

    List testList = List();
    
    try {
    
      var s = testList[3];
    
      //代码逻辑
    
    } on IntegerDivisionByZeroException {
    
      //使用on关键字,捕获特定类型的异常
    
    } on NoSuchMethodError catch (e) {
    
      //使用on关键字,捕获特定类型的异常
    
      //代码段可以有多个 on / catch 块来处理多个异常
    
    } catch (error, stacktrace) {
    
      // 没有指定类型,处理所有错误
    
      //catch 最多提供两个可选参数
    
      //第一个参数 error 类型为 Object,也就是异常是可以抛出任意对象。
    
      //第二个参数 stacktrace,表示异常堆栈。
    
      print('Something really unknown error: $error');
    
      print('Something really unknown stacktrace: $stacktrace');
    
      throw '抛出异常关键';
    
      //throw 之后的代码将不会执行
    
      //throw new FormatException();
    
    } finally {
    
      // 在throw之前先执行finally代码块
      print("this is finally");
    
    }

    输出结果:

    Dart中的每个异常类型都是内置类 Exception 的子类型。Dart可以通过扩展现有异常来创建自定义异常。定义自定义异常的语法如下所示

    语法:定义异常

    class Custom_exception_Name implements Exception {
    
       // can contain constructors, variables and methods
    
    }
    eg:
    
    class AmtException implements Exception {
    
       String errMsg() => 'Amount should be greater than zero';
    
    }  
    
    throw new AmtException();

    2、异步异常

    try-catch 代码块不能捕获到异步异常,使用 await 关键字声明的同步调用,属于同步异常范围,可以通过 try-catch 捕获。

    使用 catchError 捕获异步异常,第一个参数为 Function error 类型,第二个参数为 {bool test(Object error)},是一个判断表达式,当此表达式返回值为 true 时,表示需要执行 catch 逻辑,如果返回 false,则不执行 catch 逻辑,即会成为未捕获的异常,默认不传时 认为是true。

    这里的作用是可以精细化的处理异常,可以理解为同步异常中强化版的 on 关键字,

    入参至多两个 分别为error 和 stack,均可选。

    Future(() {
    }).then((value){ }).catchError((error, stack) { }); Future.delayed(Duration(seconds:
    1)).then((e) => Future.error("xxx"));

      二、Flutter异常捕获、抛出

    为了捕获并上报异常,可以把应用运行在一个自定义的 Zone 里面。 Zones 为代码建立执行上下文环境。在这个上下文环境中,所有发生的异常在抛出 onError 时都能够很容易地被捕获到。

    Dart中有一个runZoned(...) 方法,可以给执行对象指定一个Zone。Zone表示一个代码执行的环境范围,为了方便理解,读者可以将Zone类比为一个代码执行沙箱,不同沙箱的之间是隔离的,沙箱可以捕获、拦截或修改一些代码行为,如Zone中可以捕获日志输出、Timer创建、微任务调度的行为,同时Zone也可以捕获所有未处理的异常。下面我们看看runZoned(...)方法定义:

    R runZoned<R>(R body(), {
    
        Map zoneValues, 
    
        ZoneSpecification zoneSpecification,
    
        Function onError,
    
    })

    参数含义可参考《Flutter实战》https://book.flutterchina.club/chapter2/thread_model_and_error_report.html

    在下面的例子中,将会把应用运行在一个新的 Zone 里面并捕获所有错误,在 1.17 之前的 Flutter 版本里,你可以通过 onError() 回调捕获所有的异常。

    runZoned<Future<void>>(() async {
    
      runApp(MyApp());
    
    }, onError: (error, stackTrace) {
    
      // Whenever an error occurs, call the `_reportError` function. This sends
    
      // Dart errors to the dev console or Sentry depending on the environment.
    
      _reportError(error, stackTrace);
    
    });

    在包含了 Dart 2.8 的 Flutter 1.17 中,使用 runZonedGuarded:

    runZonedGuarded<Future<void>>(() async {
    
      runApp(MyApp());
    
    }, (Object error, StackTrace stackTrace) {
    
      // Whenever an error occurs, call the `_reportError` function. This sends
    
      // Dart errors to the dev console or Sentry depending on the environment.
    
      _reportError(error, stackTrace);
    
    });

     

    除了 Dart 异常,Flutter 也能抛出其他的异常,比如调用原生代码发生的平台异常。这种类型的异常也同样是需要上报的。

    为了捕获 Flutter 异常,需要重写 FlutterError.onError 属性。在开发环境下,可以将异常格式化输出到控制台。在生产环境下,可以把异常传递给上个步骤中的 onError 回调。

    大致步骤如下:

    Future<Null> main() async {
    
      //重写FlutterError.onError
    
      FlutterError.onError = (FlutterErrorDetails details) {
    
        if (isInDebugMode) {
    
          // In development mode, simply print to console.
    
          FlutterError.dumpErrorToConsole(details);
    
        } else {
    
          // In production mode, report to the application zone to report to
    
          // Sentry.
    
          Zone.current.handleUncaughtError(details.exception, details.stack);
    
        }
    
      };
    
      //使用runZonedGuarded捕获日志输出、Timer创建、微任务调度的行为、所有未处理的异常
    
      runZonedGuarded<Future<Null>>(
    
        () async {
    
          runApp(MyApp());
    
        },
    
        (error, stackTrace) async {
    
          await _reportErrorAndLog(error, stackTrace);
    
        },
    
        zoneSpecification: ZoneSpecification(
    
          print: (Zone self, ZoneDelegate parent, Zone zone, String line) async {
    
            await collectLog(line); // 收集日志
    
          },
    
        ),
    
      );
    
    }
    
    Future<Null> collectLog(String line) async {
      //收集日志
    }
    
    //上报错误和日志逻辑
    
    Future<Null> _reportErrorAndLog(dynamic error, dynamic stackTrace) async {
    
      print('Caught error: $error');
    
      if (isInDebugMode) {
    
        print(stackTrace);
    
        print('In dev mode. Not sending report to Sentry.io.');
    
        return;
      }
    
      //TODO: response 为上传请求结果
    
      if (response.isSuccessful) {
        print('Success!');
      } else {
        print('Failed to report to Sentry.io: ${response}');
      }
    }
    //判断debug及release环境
    
    bool get isInDebugMode {
    
      bool inDebugMode = false;
    
      assert(inDebugMode = true);
    
      return inDebugMode;
    }

     

    参考:

    https://book.flutterchina.club/chapter2/thread_model_and_error_report.html

    https://flutter.cn/docs/cookbook/maintenance/error-reporting#5-catch-and-report-dart-errors

    https://juejin.cn/post/6906274131394691085 

     

     

  • 相关阅读:
    内置函数二
    内置函数
    【MySQL】纲举目张:打通MySQL架构和业务的任督二脉
    关闭服务器节能模式
    透明大页
    【MySQL】MySQ 8.0启用HugePage
    运维安全之Tripwire
    七字诀,不再憋屈的运维
    利用钉钉机器人发送告警信息
    【MySQL】MySQL 8.0支持utf8mb4
  • 原文地址:https://www.cnblogs.com/lulushen/p/14142510.html
Copyright © 2020-2023  润新知