技术实践第二期|Flutter异常捕获
简介:应用性能稳定是良好用户体验中非常关键的一环,为了更好保障应用性能稳定,异常捕获在保证线上产品稳定中扮演着至关重要的角色。我们团队在推出了U-APM移动应用性能监控的产品后,帮助开发者定位并解决掉很多线上的疑难杂症。随着使用人数的增多,关注度的提高,在拜访客户和开发者的留言中,很多开发者都提出希望该产品可以支持flutter框架的异常捕获。本身我并没有做过flutter开发,所以主要是通过在现有产品能力基础上做插件实现异常的上报,这篇文章就记录我学习flutter错误处理的过程和遇到的问题。
作者:友盟+技术专家 彦克
一、背景
应用性能稳定是良好用户体验中非常关键的一环,为了更好保障应用性能稳定,异常捕获在保证线上产品稳定中扮演着至关重要的角色。我们团队在推出了U-APM移动应用性能监控的产品后,帮助开发者定位并解决掉很多线上的疑难杂症。随着使用人数的增多,关注度的提高,在拜访客户和开发者的留言中,很多开发者都提出希望该产品可以支持flutter框架的异常捕获。本身我并没有做过flutter开发,所以主要是通过在现有产品能力基础上做插件实现异常的上报,这篇文章就记录我学习flutter错误处理的过程和遇到的问题。
二、Flutter异常
Flutter 异常指的是,Flutter 程序中 Dart 代码运行时意外发生的错误事件。
三、Flutter异常特点
Dart是单进程机制,所以在这个进程中出现问题时仅仅会影响当前进程,Dart 采用事件循环的机制来运行任务,当某个任务发生异常并没有被捕获时,程序并不会退出,而直接导致的结果是当前任务的后续代码就不会被执行了,也就是说一个任务中的异常是不会影响其它任务执行的,各个任务的运行状态是互相独立的。
如:我们可以通过与 Java 类似的 try-catch 机制来捕获它。但与 Java 不同的是,Dart 程序不强制要求我们必须处理异常。
四、Flutter异常分类
在Flutter开发中,根据异常来源的不同,可以将异常分为Framework异常和App异常。Flutter对这两种异常提供了不同的捕获方式,Framework异常是由Flutter框架引发的异常,通常是由于错误的应用代码造成Flutter框架底层的异常判断引起的。而对于App异常,就是应用代码的异常,通常由未处理应用层其他模块所抛出的异常引起。根据异常代码的执行时序,App 异常可以分为两类,即同步异常和异步异常。
五、捕获方式
1.App 异常的捕获方式
捕获同步异常使用try-catch 机制:
// 使用 try-catch 捕获同步异常
try {
throw StateError('This is a Dart exception.');
}
catch(e) {
print(e);
}
捕获异步异常使用Future 提供的 catchError 语句:
// 使用 catchError 捕获异步异常
Future.delayed(Duration(seconds: 1))
.then((e) => throw StateError('This is a Dart exception in Future.'))
.catchError((e)=>print(e));
看到这里估计很多人心里会问,就不能有一种方式既可以监控同步又可以监控异步异常吗?
答案是有的。
Flutter 提供了 Zone.runZoned 方法来管理代码中的所有异常。我们可以给代码执行对象指定一个Zone,在 Dart 中,Zone 表示一个代码执行的环境范围,其概念类似沙盒,不同沙盒之间是互相隔离的。如果我们想要观察沙盒中代码执行出现的异常,沙盒提供了 onError 回调函数,拦截那些在代码执行对象中的未捕获异常。废话不多说,
Show me the code!
runZoned(() {
// 同步异常
throw StateError('This is a Dart exception.');
}, onError: (dynamic e, StackTrace stack) {
print('Sync error caught by zone');
});
runZoned(() {
// 异步异常
Future.delayed(Duration(seconds: 1))
.then((e) => throw StateError('This is a Dart exception in Future.'));
}, onError: (dynamic e, StackTrace stack) {
print('Async error aught by zone');
});
为了能够集中捕获 Flutter 应用中的未处理异常,最终我把main函数中的 runApp 语句也放置在 Zone 中。这样在检测到代码中运行异常时,就能根据获取到的异常上下文信息,进行统一处理了:
runZoned>(() async {
runApp(MyApp());
}, onError: (error, stackTrace) async {
//Do sth for error
});
2.Framework异常捕获方式
Flutter 框架为我们在很多关键的方法进行了异常捕获。如果我们想自己上报异常,只需要提供一个自定义的错误处理回调即可,如:
void main() {
FlutterError.onError = (FlutterErrorDetails details) {
reportError(details);
};
...
}
有没有一套从天而降的代码,能够统一处理以上异常呢?
3.总结(一套代码捕获所有异常)
runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();
FlutterError.onError = (FlutterErrorDetails details) {
myErrorsHandler.onError(details.exception,details.stack);
};
runApp(MyApp());
}, (Object error, StackTrace stack) {
myErrorsHandler.onError(error, stack);
});
代码中出现了一句,上诉从没有出现过的代码即WidgetsFlutterBinding.ensureInitialized(),当我把这行代码注释掉的时候,框架异常是捕获不到的。
当时困扰了好久最后终于查到了原因:
上图是Flutter的架构层,WidgetFlutterBinding用于与 Flutter 引擎交互。 我们的APM产品需要调用 native 代码来初始化,并且由于插件需要使用平台 channel 来调用 native 代码,这是异步完成的,因此必须调用ensureInitialized()确保你有一个 WidgetsBinding 的实例.
来自 docs :
Returns an instance of the WidgetsBinding, creating and initializing it if necessary. If one is created, it will be a WidgetsFlutterBinding. If one was previously initialized, then it will at least implement WidgetsBinding.
注:如果你的应用在runApp 中调用了 WidgetsFlutterBinding.ensureInitialized() 方法来进行一些初始化操作,则必须在runZonedGuarded中调用WidgetsFlutterBinding.ensureInitialized()
六、异常上报
异常上报的整体方案是通过已有的插件增加接口,桥接Android APM 和 iOS APM库的自定义异常上报接口。
插件增加函数
static void postException(error, stack) {
List args = [error,stack];
//将异常和堆栈上报至umapm
_channel.invokeMethod("postException",args);
}
Android 端调用自定义异常上报:
private void postException(List args){
String error = (String)args.get(0);
String stack = (String)args.get(1);
UMCrash.generateCustomLog(stack,error);
}
iOS端调用自定义异常上报:
if ([@"postException" isEqualToString:call.method]){
NSString* error = arguments[0];
NSString* stack = arguments[1];
[UMCrash reportExceptionWithName:@"Flutter" reason:error stackTrace:stack terminateProgram:NO];
}
以上就是本期干货内容的介绍,希望我们的技术内容可以更好地帮助开发者们解决问题,我们将陪伴开发者们一起进步,一起成长。
原文链接
本文为阿里云原创内容,未经允许不得转载。
技术实践第二期|Flutter异常捕获的更多相关文章
- Flutter异常监控 - 壹 | 从Zone说起
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情 如果你正需要处理Flutter异常捕获,那么恭喜你,找对地了,这里从根源上给你准备了Flutter异常捕获 ...
- Flutter异常监控 - 叁 | 从bugsnag源码学习如何追溯异常产生路径
如果觉得文章对你有帮助,点赞.收藏.关注.评论,一键四连支持,你的支持就是我创作最大的动力. ️ 本文原创听蝉 公众号:码里特别有禅 欢迎关注原创技术文章第一时间推送 ️ 前言 没错,继Flutte ...
- Flutter异常监控 - 贰 | 框架Catcher原理分析
前言 在给 Flutter 应用做异常监控的时候,一开始我是拒绝滴,如果不考虑 Flutter Engine 和 native 侧的监控,用我另一篇文章中不得不知道的 Flutter 异常捕获知识点 ...
- 网易云社区有奖问答活动第二期——技术领导力、深入分布式、PHP圣经、Linux运维、Unity……三月热点图书等你拿!
网易云社区第二期有奖问答活动开始了!(第一期活动已结束:人工智能图书大抽奖!) 欢迎积极参与网易云社区,讨论问题,交流心得.我们本期准备了一批技术领域热点图书,送给参与社区的朋友们,将以抽奖的形式送出 ...
- 祝贺|合肥.NET俱乐部第二期技术沙龙活动圆满成功
热烈祝贺合肥.NET俱乐部第二期技术沙龙圆满成功,感恩参与活动的每一位小伙伴!正是因为有你们才促成了这次聚会的成功.现对此次活动进行简单回顾并附上精彩的活动图片,每一位参与活动者名单,以及此次活动讲师 ...
- Redis数据库云端最佳技术实践
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯云数据库 TencentDB发表于云+社区专栏 邹鹏,腾讯高级工程师,腾讯云数据库Redis负责人,多年数据库.网络安全研发经验. ...
- 灵雀云Istio技术实践专题整理
Istio技术实践专题(1) Service Mesh Istio 基本概念和架构基础 Istio被称作Kubernetes的最佳云原生拍档.从今天起,我们推出"Istio技术实践" ...
- Flutter异常监控 - 肆 | Rollbar源码赏析
一. Rollbar可以帮你解决哪些问题 无特别说明,文中Rollbar统指Rollbar-flutter 1. 代码复用 Rollbar官方文档说是纯Dart实现,该特征意味着自带"代码复 ...
- 寻找大学目标及行动步骤——记ITAEM团队第二期宣讲会(2014.05.14)
·昨晚8:00-9:40.在 钟海楼03029 ,进行了ITAEM团队第二期宣讲会(第一期见第一期宣讲会总结).来參加的主要是大一学生.以信院为主.也有法学院.文学院的同学. 在宣讲会中,大家都比較积 ...
- 微信团队原创分享:iOS版微信的内存监控系统技术实践
本文来自微信开发团队yangyang的技术分享. 一.前言 FOOM(Foreground Out Of Memory),是指App在前台因消耗内存过多引起系统强杀.对用户而言,表现跟crash一样. ...
随机推荐
- GaussDB(分布式)实例故障处理
本文分享自华为云社区<GaussDB(分布式)实例故障处理>,作者:subverter. 一.说明 GaussDB Kernel实例出现故障时,可以按照本节的办法进行实例快速修复. 1.执 ...
- Swift self, Self, ==, === 傻傻分不清楚?
本文首发于 Ficow Shen's Blog,原文地址: Swift self, Self, ==, === 傻傻分不清楚?. 内容概览 前言 self 和 Self == 和 === 总结 前言 ...
- 构建个人博客网站(基于Python Flask)
本文由 Ficow Shen 首发于 Ficow Shen's Blog. 文章概览 前言 Sketch HTML, CSS, JavaScript Python & Flask & ...
- TCL基本语法2
TCL基本语法2 1.format和scan 两个基本的函数,和C语言中的sprintf和scanf的作用基本相同.format将不同类型的数据压缩在字符串中,scan将字符串中的数据提取出来. se ...
- Python数据类型---列表、元祖、字典【详解】
一.列表(List) 1.列表可以用来存储不同的数据类型,使用 [ ] e.g. 1 service = ['http','ssh','ftp'] 2.列表是有索引的,也就是可以通过下标来访问数据 3 ...
- System.gc 之后到底发生了什么 ?
本文基于 OpenJDK17 进行讨论 在 JDK NIO 针对堆外内存的分配场景中,我们经常会看到 System.gc 的身影,比如当我们通过 FileChannel#map 对文件进行内存映射的时 ...
- Refresh Clean Code
这是一本被前辈称赞, 另一个马丁的知名著作, 被赋予学习如何写出漂亮代码的教皇级手册, 最近(再)浏览, 有诸多感受. 总结一下就是如果你是新手, 可能看优秀的open source学习更好; 如果你 ...
- OpenHarmony创新赛|赋能直播第五期
OpenHarmony创新赛赋能直播课程即将再次与大家见面!本期基于之前的青蛙影院的UI界面设计的课程,介绍综合性APP的需求介绍和技术栈整合等内容.此外,课程同步赋能OpenHarmony创新赛, ...
- 前端使用 Konva 实现可视化设计器(4)
给上一章做一个补充,就是实现通过上下左右按键移动所选节点. 继续求 Star ,希望大家多多一键三连,十分感谢大家的支持~ 创作不易,Star 50 个,创作加速! github源码 gitee源码 ...
- 报名开启 | HarmonyOS第一课“营”在暑期系列直播
<HarmonyOS第一课>2023年再次启航! 特邀HarmonyOS布道师云集华为开发者联盟直播间 聚焦HarmonyOS 4版本新特性 邀您一同学习赢好礼! 你准备好了吗? ↓↓↓预 ...