Flutter学习四:Flutter开发基础(六)调试Flutter应用

目录

0 引言

1 Flutter异常捕获

1.1 Dart单线程模型

1.2 Flutter异常捕获

1.2.1 Flutter框架异常捕获

1.2.1.1  Flutter默认异常捕获方式

1.2.1.2 自己捕获异常并上报

1.2.2  其他异常捕获与日志收集

1.2.3 最终的错误上报代码


0 引言

本文是对第二版序 | 《Flutter实战·第二版》 (flutterchina.club)的学习和总结。

1 Flutter异常捕获

1.1 Dart单线程模型

  • Java 和 Objective-C都是多线程模型的编程语言,任意一个线程触发异常且该异常未被捕获时,就会导致整个进程退出。
  • Dart 和 JavaScript 都是单线程模型,如果程序发生异常且没有被捕获,程序不会终止。

Dart 大致运行原理:

Dart 在单线程中是以消息循环机制来运行的,其中包含两个任务队列:

  • 一个是“微任务队列” microtask queue
  • 另一个叫做“事件队列” event queue
  • 微任务队列的执行优先级高于事件队列。

Dart线程运行过程:

  1. 入口函数 main() 执行完后,消息循环机制便启动了。
  2. 首先会按照先进先出的顺序逐个执行微任务队列中的任务,
  3. 事件任务执行完毕后程序便会退出,
  4. 但是在事件任务执行的过程中也可以插入新的微任务和事件任务,
  5. 在这种情况下,整个线程的执行过程便是一直在循环,不会退出,
  6. 而Flutter中,主线程的执行过程正是如此,永不终止。

在Dart中:

  • 所有的外部事件任务都在事件队列中,如IO、计时器、点击、以及绘制事件等,
  • 微任务通常来源于Dart内部,并且微任务非常少,因为微任务队列优先级高,如果微任务太多,执行时间总和就越久,事件队列任务的延迟也就越久,对于GUI应用来说最直观的表现就是比较卡,所以必须得保证微任务队列不会太长。
  • 可以通过Future.microtask(…)方法向微任务队列插入一个任务。
  • 在事件循环中,当某个任务发生异常并没有被捕获时,程序并不会退出,而直接导致的结果是当前任务的后续代码就不会被执行了,也就是说一个任务中的异常是不会影响其他任务执行的。

1.2 Flutter异常捕获

Dart中可以通过try/catch/finally来捕获代码块异常,这个和其他编程语言类似。

1.2.1 Flutter框架异常捕获

1.2.1.1  Flutter默认异常捕获方式

在发生异常时,Flutter默认的处理方式是弹一个ErrorWidget

@override
void performRebuild() {
 ...
  try {
    //执行build方法  
    built = build();
  } catch (e, stack) {
    // 有异常时则弹出错误提示  
    built = ErrorWidget.builder(_debugReportException('building $this', e, stack));
  } 
  ...
}      

1.2.1.2 自己捕获异常并上报

//1.查看_debugReportException的源码来确定异常捕捉的具体实现方式。
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;
}

//2.核心的是FlutterError.reportError(details);这一句。进入后发现:
static void reportError(FlutterErrorDetails details) {
  ...
  if (onError != null)
    onError(details); //调用了onError回调
}

/*
3. 继续跟踪这里的onError就会发现它是FlutterError的一个静态属性,
   有个名为dumpErrorToConsole的默认处理方法。
*/
static FlutterExceptionHandler onError = dumpErrorToConsole;

如果我们想自己上报异常,只需要提供一个自定义的错误处理回调即可,如:

void reportErrorAndLog(FlutterErrorDetails details){
    ... //上报错误和日志逻辑
}

void main() {
  FlutterError.onError = (FlutterErrorDetails details) {
    reportErrorAndLog(details);
  };
 ...
}

1.2.2  其他异常捕获与日志收集

在Dart中,异常分两类:同步异常和异步异常

  • 同步异常可以通过try/catch捕获,
  • 异步异常可以使用runZoned(...) 方法

例如下面的代码是捕获不了Future的异常的: 

try{
    Future.delayed(Duration(seconds: 1)).then((e) => Future.error("xxx"));
}catch (e){
    print(e)
}

Dart中有一个runZoned(...) 方法,有两个参数:

  • zoneValues: Zone 的私有数据,可以通过实例zone[key]获取。
  • zoneSpecification:Zone的一些配置,可以自定义一些代码行为,比如拦截print收集日志,拦截未处理的异步错误并进行上报。
//runZoned(...)方法定义:
R runZoned<R>(R body(), {
    Map zoneValues, 
    ZoneSpecification zoneSpecification,
}) 
//runZoned(...)方法使用示例
/*
   拦截print,收集日志
   拦截未处理的异步错误,并进行上报
*/
runZoned(
  () => runApp(MyApp()),
  zoneSpecification: ZoneSpecification(
    // 拦截print
    print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
      collectLog(line);
      parent.print(zone, "Interceptor: $line");
    },
    // 拦截未处理的异步错误
    handleUncaughtError: (Zone self, ZoneDelegate parent, Zone zone,
                          Object error, StackTrace stackTrace) {
       reportErrorAndLog(details);     
       parent.print(zone, '${error.toString()} $stackTrace');
    },
  ),
);


void collectLog(String line){
    ... //收集日志
}

void reportErrorAndLog(FlutterErrorDetails details){
    ... //上报错误和日志逻辑
}

1.2.3 最终的错误上报代码

void collectLog(String line){
    ... //收集日志
}

void reportErrorAndLog(FlutterErrorDetails details){
    ... //上报错误和日志逻辑
}

FlutterErrorDetails makeDetails(Object obj, StackTrace stack){
    ...// 构建错误信息
}

void main() {
  var onError = FlutterError.onError; //先将 onerror 保存起来
  FlutterError.onError = (FlutterErrorDetails details) {
    onError?.call(details); //调用默认的onError
    reportErrorAndLog(details); //上报
  };
  runZoned(
  () => runApp(MyApp()),
  zoneSpecification: ZoneSpecification(
    // 拦截print
    print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
      collectLog(line);
      parent.print(zone, "Interceptor: $line");
    },
    // 拦截未处理的异步错误
    handleUncaughtError: (Zone self, ZoneDelegate parent, Zone zone,
                          Object error, StackTrace stackTrace) {
      reportErrorAndLog(details);
      parent.print(zone, '${error.toString()} $stackTrace');
    },
  ),
 );
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《Lua程序设计》--学习2

表 Lua语言中的表本质上是一种辅助数组&#xff08;associative array&#xff09;&#xff0c;这种数组不仅可以使用数值作为索引&#xff0c;也可以使用字符串或其他任意类型的值作为索引&#xff08;nil除外&#xff09;。 Lua语言中的表要么是值要么是变量&#xff0c;它…

防火墙基本原理详解

概要 防火墙是可信和不可信网络之间的一道屏障&#xff0c;通常用在LAN和WAN之间。它通常放置在转发路径中&#xff0c;目的是让所有数据包都必须由防火墙检查&#xff0c;然后根据策略来决定是丢弃或允许这些数据包通过。例如&#xff1a; 如上图&#xff0c;LAN有一台主机和一…

【macOS 系列】如何在mac 邮件客户端配置QQ邮箱和第二个账号

文章目录 一、配置QQ邮箱二、添加新的账户 一、配置QQ邮箱 需要在QQ邮箱账户设置中开启&#xff1a; 开启时&#xff0c;会让你发短信到指定号码&#xff0c;然后就会弹出一个验证码 也就是添加邮箱的密码不是QQ密码&#xff0c;而是这个验证码&#xff0c;这个可以生成多个&…

【OpenGL】读取视频并渲染

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍读取视频并渲染。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷路&#…

ELK实验部署过程

ELK集群部署环境准备 配置ELK日志分析系统 192.168.1.51 elk-node1 es、logstash、kibana 192.168.1.52 elk-node2 es、logstash 192.168.1.53 apache logstash &#xff08;我这里是把虚拟机的配置全部都改为2核3G的&#xff09; 2台linux 第1台&#xff1a;elk-nod…

【数据库原理】MyShop 商城数据库设计(SQL server)

MyShop 商城数据库设计 项目背景定义课程设计要求概念结构设计逻辑结构设计数据结构的描述用户信息数据结构的描述地址信息数据结构的描述商品类别数据结构的描述商品数据结构的描述购物车数据结构的描述订单数据结构的描述订单项数据结构的描述 物理结构设计用户表结构地址表结…

STM32——GPIO配置

文章目录 一、GPIO八种模式1. 输入2. 输出3. 如何选择GPIO的模式 二、库函数GPIO配置1. 配置代码2.参数设置 一、GPIO八种模式 GPIO的输入输出是对于STM32单片机来说的。以下仅为个人粗略笔记&#xff0c;内部电路分析可参考博客https://blog.csdn.net/k666499436/article/det…

计算机网络_ 1.3 网络核心(数据交换_电路交换_多路复用)

计算机网络_数据交换_电路交换_多路复用 多路复用频分多路复用FDM时分多路复用TDM波分多路复用WDM码分多路复用CDM 多路复用 多路复用&#xff08;Multiplexing&#xff09;&#xff0c;简称复用&#xff0c;是通信技术的基本概念。 链路/网络资源&#xff08;如带宽&#x…

【K8S系列】如何高效查看 k8s日志

序言 你只管努力&#xff0c;其他交给时间&#xff0c;时间会证明一切。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级论点蓝色&#xff1a;用来标记二级论点 Kubernetes (k8s) 是一个容器编排平台&#x…

docker安装失败 应用程序无法启动,因为应用程序的并行配置不正确

问题描述 报错“应用程序无法启动&#xff0c;因为应用程序的并行配置不正确”。 配置&#xff1a;windows10 解决过程 网上的解决方案有三种&#xff1a; 启动windows服务Windows Modules Installer。运行sxstrace.exe。安装visual c相关依赖。下载visual studio installer…

1.6 OSI 七层参考模型

OSI 参考模型 OSI参考模型解释的通信过程OSI参考模型数据封装与通信过程物理层功能数据链路层功能网络层的功能传输层功能会话层功能表示层功能应用层功能 开放系统互连 (OSI)参考模型是由国际标准化组织 (ISO) 于1984年提出的分层网络体系结构模型目的是支持异构网络系统的互联…

Selenium--做任何你想做的事情

大家好&#xff0c;今天为大家介绍Selenium自动化浏览器。就是这样&#xff01;你可以通过这种力量做任何你想做的事情。 “getDevTools() 方法返回新的 Chrome DevTools 对象&#xff0c;允许您使用 send() 方法发送针对 CDP 的内置 Selenium 命令。这些命令是包装方法&#x…

k8s Label 2

在 k8s 中&#xff0c;我们会轻轻松松的部署几十上百个微服务&#xff0c;这些微服务的版本&#xff0c;副本数的不同进而会带出更多的 pod 这么多的 pod &#xff0c;如何才能高效的将他们组织起来的&#xff0c;如果组织不好便会让管理微服务变得混乱不堪&#xff0c;杂乱无…

C#(四十九)之关于string的一些函数

1&#xff1a;startswith 字符串以。。。开头 // startswith 字符串以。。。开头string[] strArr { "asd","azx","qwe","aser","asdfgh"};for (int i 0; i < strArr.Length; i){if(strArr[i].StartsWith("as&qu…

LiangGaRy-学习笔记-Day28

1、回顾知识 1.1、docker启动MySQL 安装docker #准备好二进制的包 [rootNode2 ~]# ls docker-20.10.9.tgz docker-20.10.9.tgz [rootNode2 ~]# #解压docker的二进制包 [rootNode2 ~]# tar -xf docker-20.10.9.tgz #把它移动到/usr/local/下 [rootNode2 ~]# mv docker /usr/…

logback-spring.xml详解

本文来写说下logback-spring.xml相关的知识与概念 文章目录 概述configuration元素定义上下文名称定义变量appender组件RollingFileAppender配置logger配置root配置ELK的配置输出logback状态数据异步输出日志代码中的日志格式本文小结 概述 对于xml日志文件的配置&#xff0c;大…

语义分割大模型RSPrompter论文阅读

论文链接 RSPrompter: Learning to Prompt for Remote Sensing Instance Segmentation based on Visual Foundation Model 开源代码链接 RSPrompter 论文阅读 摘要 Abstract—Leveraging vast training data (SA-1B), the foundation Segment Anything Model (SAM) propo…

遗传算法(GA)优化后RBF神经网络优化分析(Matlab代码实现)

目录 1 遗传算法 2 RBF神经网络 3 Matlab代码实现 4 结果 1 遗传算法 遗传算法是一种模拟自然界进化过程的优化算法。它通过模拟生物进化的遗传、交叉和变异等过程&#xff0c;来搜索最优解或近似最优解。 遗传算法的基本步骤如下&#xff1a; 初始化种群&#xff1a;随机生成…

SPSS读取纯文本文件

纯文本文件是通用的一种格式文件&#xff0c;根据纯文本文件中数据的排序方式&#xff0c;可以将其分为自由格式和固定格式。自由格式文本文件的数据项之间必须有分隔符&#xff0c;固定格式数据项之间不需要分隔符。 1.以自由格式读取数据 &#xff08;1&#xff09;选择“文…

自然语言处理从入门到应用——预训练模型总览:预训练模型的拓展

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 相关文章&#xff1a; 预训练模型总览&#xff1a;从宏观视角了解预训练模型 预训练模型总览&#xff1a;词嵌入的两大范式 预训练模型总览&#xff1a;两大任务类型 预训练模型总览&#xff1a;预训练模型的拓展 …