简介:应用性能稳定是良好用户体验中非常关键的一环,为了更好保障应用性能稳定,异常捕获在保证线上产品稳定中扮演着至关重要的角色。我们团队在推出了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异常捕获相关推荐

  1. 广州技术沙龙第二期活动总结

    赖勇浩(http://laiyonghao.com) 总述 2009 年 9 月 19 日,在众多朋友的鼎力支持下,广州技术沙龙第二期开始了!来自包含但不限于新浪.金山.网易.腾讯.梦境.4399.c ...

  2. OPPO技术开放日第二期启动,聚焦碎片化场景下的流量探索

    继首期OPPO技术开放日的成功举办,得到广大开发者的热烈反响,OPPO 技术开放日系列沙龙第二期正在紧锣密鼓地筹备中,并将于2018年8月10日下午,在北京Mee Park隆重举行. 届时,众多行业大 ...

  3. DeviceOne开发技术周报第二期-技术文章、优秀项目展示(四季旅行网,爱抢券)...

    资讯 官方的资讯主要是给大家带来了一批新组件的上线,下面我来列举一下:边界视图.PDF阅读器.画廊视图.极光推送.加速度传感器.计步器.指纹识别等. 开发者上线的组件有以下一些:滑动选择框.Cilic ...

  4. linux下下载fnl数据,「技术讲堂第二期」|不用到处找,FNL数据直接用!

    FNL是National Centers for Environmental Prediction (NCEP)提供的一套覆盖全球大气的多变量的(如:风场.温度.位势高度等).空间均匀分布的(水平分辨 ...

  5. 免费直播 | 宏基因组云讲堂第二期由刘永鑫博士主持,特邀王金锋副研究员分享“用时序微生物组数据重现生物膜装配的动态过程”...

    博彩众家之长,积微成就突破.为促进我国宏基因组研究领域的学术交流和技术分享,推动微生物组领域的发展,"宏基因组"公众号联合国内外优秀人才组织"易生信-宏基因组 积微学术论 ...

  6. ZEGO Meetup 第二期 | 视频直播+的技术实践之道

    从2016年到2017年,视频直播行业从爆发走向成熟.2017年与2018年之交,直播行业又焕发了第二春,让人憧憬是否还有第三春. 起起伏伏的是行业的风口和趋势,稳步前进的是技术的实践之道.是采用开源 ...

  7. 【Flutter】Future 异步编程 ( 简介 | then 方法 | 异常捕获 | async、await 关键字 | whenComplete 方法 | timeout 方法 )

    文章目录 一.Future 简介 二.Future.then 使用 三.Future 异常捕获 四.Dart 练习网站 五.async.await 关键字 六.whenComplete 方法 七.ti ...

  8. 空间句法软件_【特训营报名】空间句法理论与实践应用(第二期更新版)丨城市数据派...

    最新线上特训营  授课老师专业过硬负责空间句法官方中文网站建设作为主要译者翻译空间句法奠基作<空间的社会逻辑>此课程为空间句法初级课程的第二期更新版课程内容更丰富更完善教学视频永久观看 报 ...

  9. 【北京】微软技术直通车(第二期) 之 SQL Server 2017饕餮

    微软技术直通车 本系列活动密切关注微软及周边相关技术.以微软云计算和相关产品为依托,涉及云计算.数据处理.开发工具.商用软件.物联网.人工智能等前沿科技. 系列活动邀请微软技术专家.一线开发者.成功创 ...

最新文章

  1. iis 无法连接mysql_远程无法连接SQL2000及MySQL的原因和解决办法
  2. 在Linux上安装QT4
  3. 月饼怎么吃才不胖,数据分析师教你选月饼
  4. Silverlight动画制作之From/To/By基本动画
  5. unity3d双面材质_[转]unity3d中创建双面材质
  6. 2021.10.26 Node.js笔记
  7. stl之set集合容器应用基础
  8. Chrome插件(Extensions)开发攻略
  9. atitit.404错误的排查流程总结vOa6
  10. VB添加TTS语音合成
  11. 2019美赛B题完整论文
  12. android谷歌打印插件下载地址,谷歌浏览器打印插件:Print Plus
  13. android 吃鸡模拟器,《刺激战场模拟器》电脑版 逍遥安卓模拟器智能键吃鸡设置...
  14. 滚雪球学 Python 番外篇之游戏世界,游戏也有 Hello World
  15. 域名注册好了怎么使用 注册域名后需要备案吗
  16. 路面坑洼检测中的视觉算法
  17. Lambda表达式的省略
  18. 免费版本在线客服迷你窗口内的开场广告语如何关闭?
  19. CTF解题思路:图片隐写
  20. Genin.一日一进步

热门文章

  1. treeview控件怎么折叠_拍摄的视频闪烁怎么办?一招就能搞定,电脑手机都适用...
  2. 小程序promise封装post请求_Promise封装微信小程序的Request请求
  3. java new一个对象的过程中发生了什么
  4. Java学习的5个阶段,助大家步步攀升
  5. Java面向对象和面向过程有什么区别?网友:傻傻分不清楚……
  6. desktop docker 无法卸载_Docker容器无法停止或移除-权限被拒绝错误
  7. raft算法_Raft算法与实现
  8. simulink和c语言开发,Simulink之嵌入式C代码生成-应用层和底层的接口
  9. java 格式化字符串_Java入门 - 语言基础 - 14.String类
  10. simulink和psim仿真结果不同_在HFSS进行AC耦合电容仿真优化怎么做?