Dart-4 异常捕获机制

1.Flutter 异常捕获机制

Dart 中可以通过 try/catch/on /finally 来捕获代码块异常,这个和其它变成语类似

try:执行的 代码,其中有可能异常,一旦发生异常,则立即跳转到catch 执行,否则catch里面的内容不执行

on: 当你需要指定异常类型的时候使用 on

catch:除非try有异常,否则不执行,使用rethrow关键词让异常传递下去

finally:不管什么情况都会执行,不过 try ,catch 里面使用了return

void exceptionTest(){
  try {
    int result = 12 ~/ 0;
    print("result is $result");
    
  }on IntegerDivisionByZeroException {
    print("Cannot deivide by zero");
  }
}

void exceptionTest2(){
  try {
    int result = 12 ~/ 0;
    print("result is $result");
    
  }catch (e,s) {
    print("The exception throw is $e");
    print("STACK TRACE \n $S");
  }
}

//case4
void exceptionTest2(){
  try {
    int result = 12 ~/ 0;
    print("result is $result");
    
  }catch (e,s) {
    print("The exception throw is $e");
    print("STACK TRACE \n $S");
  }
} finally {
  print("不管有没有异常都会执行");
}

常见异常

  • DeferredLoadException 延迟库无法加载
  • FormatException 数据类型转换异常,或解析异常
  • IntegerDivisionByZeroException 数字除以零
  • IOException IO流异常
  • NullPoingtException 空指针异常

自己实现简单的异常捕获

在Dart高效编程中一般建议继承Error或者 Exception类作为子类实现错误或者异常的抛出。

main(List args) {
  try {
    depositMoney(200);
  }catch (e) {
    print("error is $e");
  }
}

class DepositException implements Exception {

  String errorMessage() {
    return "金额不能少于0";
  }

}

void depositMoney(int amount) {
  if (amount <= 0) {
    throw new DepositException();
  }
}

2. Flutter框架异常捕获,这块不拓展,留给以后

Flutter 框架为我们在很多关键的方法进行了异常捕获。例如:当我们布局发生越界或不合规范时,Flutter会自动弹出一个错误界面,这是因为Flutter在执行build方法时添加了异常捕获,下面是源码如下:

// 系统里面的源码
@override
  void performRebuild() {
    if (!kReleaseMode && debugProfileBuildsEnabled)
      Timeline.startSync('${widget.runtimeType}',  arguments: timelineWhitelistArguments);

    assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true));
    Widget built;
    try {
      built = build();
      debugWidgetBuilderValue(widget, built);
    } catch (e, stack) {
      built = ErrorWidget.builder(
        _debugReportException(
          ErrorDescription('building $this'),
          e,
          stack,
          informationCollector: () sync* {
            yield DiagnosticsDebugCreator(DebugCreator(this));
          },
        ),
      );
    } finally {
      // We delay marking the element as clean until after calling build() so
      // that attempts to markNeedsBuild() during build() will be ignored.
      _dirty = false;
      assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(false));
    }
    try {
      _child = updateChild(_child, built, slot);
      assert(_child != null);
    } catch (e, stack) {
      built = ErrorWidget.builder(
        _debugReportException(
          ErrorDescription('building $this'),
          e,
          stack,
          informationCollector: () sync* {
            yield DiagnosticsDebugCreator(DebugCreator(this));
          },
        ),
      );
      _child = updateChild(null, built, slot);
    }

    if (!kReleaseMode && debugProfileBuildsEnabled)
      Timeline.finishSync();
  }

_debugReportException 方法中最终通过 FlutterError.reportError 将错误信息进行上报:

FlutterErrorDetails _debugReportException(
  String context,
  dynamic exception,
  StackTrace stack, {
  InformationCollector informationCollector
}) {
  //构建错误详情对象  
  final FlutterErrorDetails details = FlutterErrorDetails(
    exception: exception,
    stack: stack,
    library: 'widgets library',
    context: context,
    informationCollector: informationCollector,
  );
  //报告错误
  FlutterError.reportError(details);
  return details;
}

reportError 方法中最终通过 onError 属性处理错误信息(实际上 onError 有默认实现 dumpErrorToConsole)。我们可以通过重写 onError 属性拦截上报信息(reportError 方法):


void main() {
  FlutterError.onError = (FlutterErrorDetails details) {
    reportError(details);
  };
  runApp(FilePathProviderApplication());
}

如果我们需要自定义错误页面,则需要重写 ErrorWidget.builder:

void main() {
  ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails) {
    print(flutterErrorDetails.toString());
    return Center(
      child: Text("Flutter 崩溃了"),
    );
  };
  runApp(FilePathProviderApplication());
}

Flutter 端异常捕获实践

对于 Flutter 端的异常信息,除了能够使用 try-catch 捕获的同步异常之外,大多数情况下异常信息集中在 Flutter 端的页面渲染方面,所以我们需要重写 FlutterError.onError 用于处理框架层自动添加的异常捕获:

const bool inProduction = const bool.fromEnvironment("dart.vm.product");

FlutterError.onError = (FlutterErrorDetails details) async {
  if (inProduction) {
    Zone.current.handleUncaughtError(details.exception, details.stack);
  } else {
    FlutterError.dumpErrorToConsole(details);
  }
};

在非生产环境下,异常信息通过 FlutterError.dumpErrorToConsole(details) 交由控制台进行输出,生产环境则通过 Zone.current.handleUncaughtError(details.exception, details.stack) 将异常信息交付给 Flutter 层的全局异常捕获进行处理。

然后,我们再为整个应用程序的 Flutter 层添加全局异常捕获

runZoned>(() async {
    runApp(new HomeApp());
  }, onError: (error, stackTrace) async {
    await _reportError(error, stackTrace);
  });

你可能感兴趣的:(Dart-4 异常捕获机制)