技术实践第二期|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(),当我把这行代码注释掉的时候,框架异常是捕获不到的。

当时困扰了好久最后终于查到了原因:

Dingtalk_20211203145217.jpg

上图是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];

}

以上就是本期干货内容的介绍,希望我们的技术内容可以更好地帮助开发者们解决问题,我们将陪伴开发者们一起进步,一起成长。

原文链接
本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/511839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

请结合计算机硬件论述指令执行的过程,【计算机组成原理】计算机软硬件组成...

文章目录分层结构软件系统硬件系统I/O设备控制器存储器运算器先上张图,对计算机的软硬件组成有个大体的认识,接下来就是掰开揉碎这张大图ψ(`∇)ψ,本文绝大多数图片均为手绘分层结构其中操作系统的重要性不言而喻,也就…

F5:API 网关、流量网关发展各异,推出NGINX企阅版提供开源软件+企业级服务

作者 | 宋慧 出品 | CSDN 云计算 全球 80%互联网流量经过的 NGINX,全球有超过 4 亿个域名使用 NGINX 为载体,NGINX 无疑是成功的开源网关产品。 近日,F5 宣布 NGINX 在社区开源版本基础之上,推出NGINX企阅版(NGINX Op…

Spring Boot Serverless 实战系列“架构篇” 首发 | 光速入门函数计算

简介:如何以 Serverless 的方式运行 Spring Boot 应用? 作者 | 西流(阿里云函数计算专家) Spring Boot 是基于 Java Spring 框架的套件,它预装了 Spring 一系列的组件,开发者只需要很少的配置即可创建独立…

实现 消息提醒图标_用了5年苹果手机都不知道,原来小汽车图标是这个意思 ! ! !...

阅读本文前,请您先点击上面的“蓝色字体”,再点击“关注”,这样您就可以继续免费收到文章了。每天都会有分享,都是免费订阅,请您放心关注。注图文来源网络,侵删 …

技术分享:从双11看实时数仓Hologres高可用设计与实践

简介:本文将会从阿里巴巴双11场景出发,分析实时数仓面临的高可用挑战以及针对性设计。 2021年阿里巴巴双11完美落下为帷幕,对消费者来说是一场购物盛宴,对背后的业务支撑技术人来说,更是一场年度大考。在这场大考中&a…

操作系统如何实现:什么是宏内核、微内核

作者 | 陆小凤来源 | 码农的荒岛求生操作系统和普通的大型应用程序项目类似,都涉及代码组织方式的问题,但操作系统的独特之处在于其核心部分必须运行在内核态,kernel model,所谓内核态严格讲是指在该状态下程序拥有对硬件(hardwar…

雷神开机logo更改_九代酷睿i9加持的性能怪兽 雷神911黑武士Ⅱ评测

随着英特尔9代酷睿CPU的到来,品牌台式机也逐渐迎来了全新的升级,各大厂商也竞相抢占台式整机市场。而对于DIY组装机来说,相对于玩家门槛和售价又相对较高。国产台式机品牌雷神也抓住了这次契机,推出了“911黑武士”的第二代“911黑…

阿里云高级技术专家周晶:基于融合与协同的边缘云原生体系实践

简介:2020年 5G 商用元年以来,各种边缘场景开始火热起来,边缘计算又重回人们视野,这次的回归还伴随着云计算的普及与通信技术的颠覆式发展。边缘云作为 5G 与中心云计算的中继节点,处于云网融合、承上启下的关键位置。…

进程调度:我太难了!

作者 | 轩辕之风O来源 | 编程技术宇宙1、任务切换现在有一块CPU,但是有两个程序都想来执行,我们需要开发一个任务调度程序。只有两个程序,so easy啦!让它们交替执行就行了。为了实现切换,我们提供一个API,这…

阿里千万实例可观测采集器-iLogtail正式开源

简介:11月23日,阿里正式开源可观测数据采集器iLogtail。作为阿里内部可观测数据采集的基础设施,iLogtail承载了阿里巴巴集团、蚂蚁的日志、监控、Trace、事件等多种可观测数据的采集工作。iLogtail运行在服务器、容器、K8s、嵌入式等多种环境…

重启报错_Win10蓝屏,提示收集错误信息,反复重启报错

操作步骤:电脑为Win10系统,偶尔遇到微软Win10检测机制收集错误信息的提示,需要重启,重启之后恢复正常,但是在使用过程中收到此报错之后机器会反复的重启蓝屏提示。您可参考以下方式调试:方案一:1、按下“Wi…

一款跑在云上的定制容器专属 OS 来了——LifseaOS | 龙蜥技术

简介:如果可以把运维 API 化,那我们是不是可以把 OS 也作为一个 K8S 可以管理的资源,让 K8S 像管理容器一样管理OS? 引言 在 2021 年 10 月的云栖大会上,为云原生而生的 OS Lifsea 正式对外发布,并集成进入…

使用云效Codeup10分钟紧急修复Apache Log4j2漏洞

简介:2021年12月10日,国家信息安全漏洞共享平台(CNVD)收录了Apache Log4j2远程代码执行漏洞(CNVD-2021-95914),此漏洞是一个基于Java的日志记录工具,为Log4j的升级。作为目前最优秀的…

mysql时间相减得到天数保留两位_【敲黑板!】分布式事务数据库 —-MySQL 数据库开发规范(第四节)...

今天Amy着重为大家讲解一下关于函数的一些硬核知识,也是本文中非常重要的一个章节,记得认真看(dianzan)哦~第四节、函数4.1 字符串连接函数MySQL 数据库中字符串连接方法,需使用 CONCAT() 或 CONCAT_ WS()函数&#xf…

3类代码安全风险如何避免?

简介:企业和开发者在解决开源依赖包漏洞问题的同时,还需要考虑如何更全面地保障自己的代码数据安全。那么有哪些安全问题值得我们关注呢? 编者按:本次 Apache Log4j2 开源依赖包漏洞为所有人敲响警钟,企业的代码作为最…

手工模拟实现 Docker 容器网络!

作者 | 张彦飞allen来源 | 开发内功修炼如今服务器虚拟化技术已经发展到了深水区。现在业界已经有很多公司都迁移到容器上了。我们的开发写出来的代码大概率是要运行在容器上的。因此深刻理解容器网络的工作原理非常的重要。只有这样将来遇到问题的时候才知道该如何下手处理。网…

技术分享 | 使用 mPaaS 配置 SM2 国密加密指南

简介:随着移动智能终端的广泛应用,敏感信息极易被监控或盗取,给国家、企事业及个人带来极大政治、经济损失。金融和重要领域的各个企业正在逐步落实并完成国产密码改造工作。为解决客户侧因更换加密算法造成的种种不便,mPaaS 现已…

我的世界1.8.9无需正版的服务器,我的世界1period;8period;9服务器纯洁服地址 | 手游网游页游攻略大全...

发布时间:2015-09-26怎么创建属于自己的服务器那?开服教程为大家准备好了.如果我们想和小伙伴们联机进行玩耍的话就必须要建立一个服务器,要不然就是加入别人的服务器,那么服务器的建立方法是什么呢?我 ...标签:我的世界攻略 我的世界 我的世界开服发布…

报表功能升级|新增的这4项图表组件太好用了吧

简介:你们要的交叉透视表、词云、日历热力图、雷达图安排上啦~ 宜搭3.0上线已满一月,大家体验如何呢? 为了让大家更好地实现一站式数据加工处理及展示,我们近期针对报表板块做了升级 我们新上线了4项大家在社区呼声…

进程切换的本质是什么?

作者 | 陆小凤来源 | 码农的荒岛求生我们都知道操作系统最重要的功能之一是多任务能力,也就是可以运行超过CPU数量的程序——即进程,要想实现这一功能就必须具备将有限的CPU资源在多个进程之间分配的能力,在程序员看来,我们的程序…