关于android:Flutter异常监控-壹-从Zone说起

43次阅读

共计 3778 个字符,预计需要花费 10 分钟才能阅读完成。

如果你正须要解决 Flutter 异样捕捉,那么祝贺你,找对地了,这里从本源上给你筹备了 Flutter 异样捕捉须要是所有常识和原理,让你更粗浅意识 Flutter Zone 概念。

Zone 是什么

/// A zone represents an environment that remains stable across asynchronous
/// calls.

SDK 中形容:示意一个环境,这个环境为了保持稳定异步调用。

艰深了解 39 | 线上呈现问题,该如何做好异样捕捉与信息采集?中形容:

咱们能够给代码执行对象指定一个 Zone,在 Dart 中,Zone 示意一个代码执行的环境范畴,其概念相似沙盒,不同沙盒之间是相互隔离的。如果咱们想要察看沙盒中代码执行呈现的异样,沙盒提供了 onError 回调函数,拦挡那些在代码执行对象中的未捕捉异样。

Zone 创立

Dart 提供了 runZoned 办法,反对 Zone 的疾速创立

R runZoned<R>(R body(),
    {Map<Object?, Object?>? zoneValues,
    ZoneSpecification? zoneSpecification,
    @Deprecated("Use runZonedGuarded instead") Function? onError}) {
  • zoneValues: Zone 的公有数据,能够通过实例 zone[key] 获取,能够了解为每个“沙箱”的公有数据。
  • zoneSpecification:Zone 的一些配置,能够自定义一些代码行为,比方拦挡日志输入和谬误等

Zone 的作用

捕捉异样

import 'dart:async';

//OUTPUT:Uncaught error: Would normally kill the program
void main() {runZonedGuarded(() {Timer.run(() {throw 'Would normally kill the program';});
  }, (error, stackTrace) {print('Uncaught error: $error');
  });
}

用 try catch 一样能够捕捉,为啥要通过 Zone 来捕捉?

  1. Zone 回调收拢了异步捕捉入口,进步了可维护性。
  2. 未意料的未捕捉异样能够帮你主动捕捉到,进步便捷性。

是不是所有异样都能够捕捉到?

不是, 只能解决状况 1。

  1. Zone 默认捕捉范畴次要针对异步异样或者个别逻辑异样等惯例异样,比方 Future 中出了问题,或者逻辑解决了 1 /0,(见 Tag3),捕捉异步异样原理见简话 -Flutter 异样解决 – 掘金
  2. Dart 中另外比拟容易呈现的异样是 framework 异样,比方 build 异样等,这种异样 Zone 无奈捕捉到,起因能够参看 Flutter 异样捕捉和 Crash 解体日志收集。如果想 Zone 来解决可这样抛给它(见 Tag1)
  3. Flutter Engine 和 Native 异样,isolate 异样 不是 runZonedGuarded 和 FlutterError.onError 能解决范畴。
  4. isolate 异样解决(见 Tag2)

    原理参考特地放送 | 温故而知新,与你说说专栏的那些思考题

并发 Isolate 的异样是无奈通过 try-catch 来捕捉的。并发 Isolate 与主 Isolate 通信是采纳 SendPort 的音讯机制,而异样实质上也能够视作一种消息传递机制。所以,如果主 Isolate 想要捕捉并发 Isolate 中的异样音讯,能够给并发 Isolate 传入 SendPort。而创立 Isolate 的函数 spawn 中就恰好有一个类型为 SendPort 的 onError 参数,因而并发 Isolate 能够通过往这个参数里发送音讯,实现异样告诉。

残缺 Dart 异样捕捉代码

void main() {FlutterError.onError = (FlutterErrorDetails details) {Zone.current.handleUncaughtError(details.exception, details.stack);//Tag1
    // 或 customerReport(details);
  };

  //Tag2
  Isolate.current.addErrorListener(RawReceivePort((dynamic pair) async {
        final isolateError = pair as List<dynamic>;
        customerReport(details);
      }).sendPort,
    );

  runZoned(() => runApp(MyApp()),
    zoneSpecification: ZoneSpecification(print: (Zone self, ZoneDelegate parent, Zone zone, String line) {report(line)
      },
    ),
    onError: (Object obj, StackTrace stack) {
      //Tag3
      customerReport(e, stack);
    }
  );
}

在局部或全副代码中笼罩一组无限的办法

例如 print()scheduleMicrotask()

main() {runZoned(() {print("test");
  }, zoneSpecification: ZoneSpecification(print: (self, parent, zone, s) {parent.print(zone, "hook it: $s");
      }
  ));
}

//OUTPUT:hook it: test

下面实现的原理是什么呢?

简略讲就是 runZoned 从 root Zone fork 了一个子 Zone,print 打印时如果以后 Zone

不为空则应用以后 Zone 的 print 来打印,而不应用 root Zone 的 print 办法。具体见 Dart 中 Future、Zone、Timer 的源码学习

每次代码进入或退出区域时执行一个操作

例如启动或进行计时器,或保留堆栈跟踪。

如下例子,Zone 提供了一个 hook 点,在执行其中办法时候,能够做额定包装操作(Tag1,Tag2),比方耗时办法打印,这样在不毁坏原有代码根底上实现了无侵入的对立逻辑注入。

import 'dart:async';

final total = new Stopwatch();
final user = new Stopwatch();

final specification = ZoneSpecification(run: <R>(self, parent, zone, f) {
  //Tag1
  user.start();
  try {return parent.run(zone, f);
  } finally {
    //Tag2
    user.stop();}
});

void main() {runZoned(() {total.start();
    a();
    b();
    c().then((_) {print(total.elapsedMilliseconds);
      print(user.elapsedMilliseconds);
    });
  }, zoneSpecification: specification);
}

void a() {print('a');
}

void b() {print('b');
}

Future<void> c() {return Future.delayed(Duration(seconds: 5), () => print('c'));
}

输入:

a
b
c
5005
6

将数据(称为 Zone 本地值)与各个其余 Zone 相关联

这个作用相似 java 中的 threadlocal,每个 Zone 相当于有本人值的作用范畴,Zone 间接值的传递和共享通过 zonevalue 来实现。

import 'dart:async';

void main() {Zone firstZone = Zone.current.fork(zoneValues: {"name": "bob"});
  Zone secondZone = firstZone.fork(zoneValues: {"extra_values": 12345});
  secondZone.run(() {print(secondZone["name"]); // bob
    print(secondZone["extra_values"]); // 12345
  });
}

案例阐明:

和 Linux 相似地,当 Zone 做 Fork 的时候,会将父 Zone 所持有的 ZoneSpecification、ZoneValues 会继承下来,能够间接应用。并且是反对追加的,secondZone 在 firstZone 的根底之上,又追加了 extra_values 属性,不会因为 secondZone 的 ZoneValues 就导致 name 属性被替换掉。

如果感觉文章对你有帮忙,点赞、珍藏、关注、评论,一键四连反对,你的反对就是我创作最大的能源。

❤️ 欢送关注公众号:码里特地有禅 原创技术文章第一工夫推送 ❤️

参考链接

简话 -Flutter 异样解决 – 掘金

Zones | Dart

Brian Ford – Zones – NG-Conf 2014 – YouTube

[[Flutter] 意识 Zone 和异样解决 – 掘金](https://juejin.cn/post/712163…)

2.8 Flutter 异样捕捉 |《Flutter 实战·第二版》

特地放送 | 温故而知新,与你说说专栏的那些思考题

正文完
 0