flutter 弹窗之系列三

Overlay 部分源码

class Overlay extends StatefulWidget{...static OverlayState of(BuildContext context, {bool rootOverlay = false,Widget debugRequiredFor,})...
}
// rootOverlay: 
// 值为false, 就近查找,找到树中最近的节点; 
// 如果为true, 则去找最顶层的节点。
class OverlayState extends State<Overlay> with TickerProviderStateMixin {/// 存储所有的OverlayEntryfinal List<OverlayEntry> _entries = <OverlayEntry>[];/// 计算OverlayEntry的插入位置int _insertionIndex(OverlayEntry below, OverlayEntry above) {if (below != null) return _entries.indexOf(below);if (above != null) return _entries.indexOf(above) + 1;return _entries.length;}/// 添加一个OverlayEntry, 在`_insertionIndex(below, above)`/// OverlayEntry里可以放个[Positioned]来确定位置。void insert(OverlayEntry entry, { OverlayEntry below, OverlayEntry above })/// 同insert,添加多个void insertAll(Iterable<OverlayEntry> entries, { OverlayEntry below, OverlayEntry above })/// 更新当前的Overlayentry。将newEntries更新旧有的部分/// 将旧有未更新的部分,添加到`_insertionIndex(below, above)`void rearrange(Iterable<OverlayEntry> newEntries, { OverlayEntry below, OverlayEntry above }){final old = LinkedHashSet<OverlayEntry>.from(_entries);setState(() {_entries..clear()..addAll(newEntriesList);old.removeAll(newEntriesList);_entries.insertAll(_insertionIndex(below, above), old);});}}
class _Theatre extends MultiChildRenderObjectWidget

自定义弹出框 OverlayEntry

class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title;@overrideState<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {// 自定义Toastvoid _showOverlay({required String message,}) {// 创建一个OverlayEntry对象OverlayEntry overlayEntry = OverlayEntry(builder: (context) {// 外层使用Position进行定位,控制在Overlay中的位置return Positioned(top: MediaQuery.of(context).size.height * 0.7,child: Material(child: Container(width: MediaQuery.of(context).size.width,alignment: Alignment.center,child: Center(child: Card(color: Colors.grey,child: Padding(padding: EdgeInsets.all(8),child: Text(message),),),),),),);});// 往Overlay中插入OverlayEntryOverlay.of(context).insert(overlayEntry);// 两秒后,移除ToastFuture.delayed(const Duration(seconds: 2)).then((value) => overlayEntry.remove());}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title),),body: Center(child: GestureDetector(onTap: () {_showOverlay(message: "消息");},child: const Text('\n显示Overlay\n',),),),);}
}

避免常见sentry异常的编码技巧

Dart 空指针异常 这类错误是在flutter非常常见的异常,如果不加以关注,那么sentry会收集到非常的错误数据。

_CastError
Null check operator used on a null value
"Null check operator used on a null value" 是一个 Dart 语言中的错误提示,表示在一个空值上使用了非空检查操作符(!)。
这个错误通常发生在你使用了非空检查操作符(!)来访问一个可能为空的变量或表达式时。当你使用非空检查操作符(!)时,
你告诉编译器“我知道这个值可能为空,但是我确定它不会为空,请继续执行”。
但是,如果实际上这个值为空,那么就会抛出一个异常,即 "Null check operator used on a null value"。

 setState调用异常

原因分析

组件unmount之后,还存在setState调用,由于_element = null,此时调用_element!.markNeesBuild()就会抛出异常.

一般是异步函数回调里调用setState,导致此问题出现。因此,异步函数后,调用setState需要特别关注。

目前Flutter异步函数的场景如下:

  1. Future、async/await
  2. Timer
  3. Stream
  4. Native Channel

解决方案

出现异常的地方使用 if (mounted) setState(...);

 注意:mounted == context.mounted,但使用context前,必须保证context不为null

 

 

 重写State类

由于setState异常一般不影响应用的时候,但为了解决每次setState都需要做mounted判断的处理,比较繁琐,可以封装一个父类,对setState异常做捕获,并用日志记录。

abstract class StateWidget<T extends StatefulWidget> extends State<T> {@protectedvoid setState(VoidCallback fn) {super.setState(() {if (mounted) {fn();} else {Log.error('mounted=$mounted fn=$fn');}});}
}/// demo
class TestWidget extends StatefulWidget {@overrideState<StatefulWidget> createState() => StateTestWidget();
}class StateTestWidget extends StateWidget<TestWidget> {@overridevoid initState() {super.initState();}@overrideWidget build(BuildContext context) {// TODO: implement buildthrow UnimplementedError();}
}

弹窗showDialog组件回调函数引发父组件异常

安全写法

 自定义Dialog

可以自定义Dialog,在每次widget dispose的时候,把widget内场景的Dialog全部销毁,避免父组件已销毁,Dialog未销毁,触发的回调函数引发异常。代码如下所示:

class Dialog {BuildContext? _context;// 显示弹窗Future<void> show({required BuildContext context,required WidgetBuilder builder,bool barrierDismissible = true,Color? barrierColor = Colors.black54,String? barrierLabel,bool useSafeArea = true,bool useRootNavigator = true,RouteSettings? routeSettings,Offset? anchorPoint,}) async {remove();await showDialog(context: context,barrierDismissible: barrierDismissible,barrierColor: barrierColor,barrierLabel: barrierLabel,useSafeArea: useSafeArea,useRootNavigator: useRootNavigator,routeSettings: routeSettings,anchorPoint: anchorPoint,builder: (BuildContext context) {_context = context;return builder(context);},);}// 销毁弹窗void remove() {BuildContext? context = _context;if (context != null && context.mounted == true) {Navigator.pop(context);_context = null;}}
}

 非!判断

建议少用非!写法,对null状态做判断,如下图所示:

 说明:对于当前非常确定性非空的场景,也可能随着版本迭代的改动,导致非空。

函数参数声明

Dart允许在申明函数的时候,不申明函数参数,如下所示:

 建议:所有的函数申明,都申明函数参数,如下图所示:

 List数组index溢出

RangeError (index): Invalid value: Valid value range is empty: 1

 建议:通过index取List数组值的时候,都做index是否溢出判断,如下:

 封装扩展isRange函数

 Stream close()后,继续add()调用,出现异常

Bad state: Cannot add new events after calling close

解决方案:可以使用isClosed属性判断Stream是否已经关闭

其实Stream在flutter开发过程中,使用不多,但这里提出来是因为很多三方库内部会使用到Stream进行数据通信。

因此我们调用三方库的接口,需要保障调用顺序,例如:audioplayer dispose()之后,继续调用release()等接口会出现异常。

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

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

相关文章

数据库专题(oracle基础和进阶)

前言 本专题主要记录自己最近学的数据库&#xff0c;有兴趣一起补习的可以一起看看&#xff0c;有补充和不足之处请多多指出。希望专题可以给自己还有读者带去一点点提高。 数据库基本概念 本模块有参考&#xff1a;数据库基本概念-CSDN博客 数据库管理系统是一个由互相关联的…

[Java基础揉碎]抽象类

目录 通过问题引出 介绍 关键点 细节 ​编辑 抽象类的最佳设计模式--模版设计模式 1.先用最容易想到的方法 2.分析问题&#xff0c;提出使用模板设计模式 通过问题引出 假如我们有个动物类, 动物都有eat吃的方法, 但是具体吃什么, 我们不知道, 因为是什么动物我们不知道…

Git版本控制

这是两个学习Git推荐必看的文档&#xff0c;第一个链接是Git的官方权威文档&#xff0c;第二个链接是国内程序员在开发中&#xff0c;总结的Git快速入门教程&#xff0c;掌握这个&#xff0c;也足够应付在工作中的场景。 Git权威书籍《ProGit》中文版https://gitee.com/progit…

jdk11中自定义java类在jvm是如何被查找、加载

yym带你了解jvm源码&#xff0c;openjdk11源码&#xff0c;java类jvm加载原理 jdk11中java类在jvm是如何被1查找、2加载 以下说明的是MiDept类是如何被java classloader 和 jvm加载步骤 上源代码 public static void main(String[] args) {Thread.currentThread().setName…

Python机器学习赋能GIS:地质灾害风险评价的新方法论

地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质灾害在世界范围内频繁发生。我国除滑坡灾害外&#xff0c;还包括崩塌、泥石流、地面沉…

k8s记录-基础配置1

1、基础yaml文件格式 1.1、namespace apiVersion: v1 kind: Namespace metadata:name: namelabels:name: namekubectl apply -f namespace.yaml 1.2、Service service示例 apiVersion: v1 kind: Service metadata:name: ilanni-httpd-svcnamespace: ilanni-namespace spec:…

【代驾+顺风车+货运】全开源双端APP代驾+顺风车+货运代驾小程序源码

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 一、详细介绍 系统是基于Thinkphpuniapp开发的&#xff0c;全开源未加密&#xff0c;这套源码可以拿回去自己做二开 后台用户端司机端 功能详情介绍&#xff1a; 车主实名认证&#xff0c;驾驶证认证&#xff0c;车…

大学生实习被企业坑了,教训比较深刻

帮实习生解决一些疑惑&#xff0c;所以出了一个视频&#xff0c;大家多多支持 实习途径 1 靠自己&#xff08;招聘平台投简历&#xff0c;大专及普通大学的选择&#xff09; 2 靠关系&#xff08;亲人、老师、朋友帮推荐&#xff0c;有关系就是好&#xff09; 3 靠校招&#xf…

ROS机器人入门第四课:话题通信

文章目录 ROS机器人入门第四课&#xff1a;话题通信一、话题通信概述&#xff08;一&#xff09;概念&#xff08;二&#xff09;作用 二、话题通信基本操作需求:分析:流程:&#xff08;一&#xff09;发布方解释一些关键的ROS函数和概念&#xff1a; &#xff08;二&#xff0…

力扣刷题44-46(力扣0062/0152/0198)

62. 不同路径 题目描述&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff0c;机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。问总共有多少条不同的路径&#xff1f; 思路&#xff1a; 其实就是问(0,0)->(m-1,n-1)一共有几条路。 第一个…

office办公技能|word中的常见使用问题解决方案2.0

一、设置多级列表将表注从0开始&#xff0c;设置为从1开始 问题描述&#xff1a;word中插入题注&#xff0c;出来的是表0-1&#xff0c;不是1-1&#xff0c;怎么办&#xff1f; 写论文时&#xff0c;虽然我设置了“第一章”为一级标题&#xff0c;但是这三个字并不是自动插入的…

QMT量化交易上手

文章目录 QMT介绍基本使用代码初始化股票和行情交易量化策略示例相关链接QMT介绍 QMT是迅投公司出品量化交易客户端软件,目前只能运行在windows机器上,分为QMT 和 miniQMT两种模式,后者可以采用python API做程序化交易,极大方便了广大散户。这点上比同花顺/通信达好很多。…

软件推荐 篇三十七:安卓软件推荐IP Tools「IP工具」:全面解析网络状态与管理的必备神器

引言&#xff1a; 随着互联网的普及&#xff0c;网络已经成为我们日常生活中不可或缺的一部分。无论是工作、学习还是娱乐&#xff0c;我们都需要通过网络来进行各种操作。然而&#xff0c;网络问题的出现往往会给我们带来诸多困扰。为了更好地管理和优化网络&#xff0c;我们…

tomcat配置静态资源后无法正常访问

目录 一、场景二、配置三、访问异常四、排查五、原因六、解决 一、场景 1、将前端文件存在到指定目录 2、在tomcat配置静态资源 3、配置后无法正常访问到前端文件 二、配置 1、tomcat配置 2、静态资源 三、访问异常 四、排查 可以ping通&#xff0c;但是访问不了3080端口 …

rabbitmq 3.9.29 docker mac 管理员页面无法打开

SyntaxError: Unexpected token ‘catch’ SyntaxError: Unexpected token ‘catch’ at EJS.Compiler.compile (http://127.0.0.1:15672/js/ejs-1.0.min.js:1:6659) at new EJS (http://127.0.0.1:15672/js/ejs-1.0.min.js:1:1625) at format (http://127.0.0.1:15672/js/main…

程序员35岁会失业吗?【来自主流AI的回答】

程序员35岁会失业吗&#xff1f; 35岁被认为是程序员职业生涯的分水岭&#xff0c;许多程序员开始担忧自己的职业发展是否会受到年龄的限制。有人担心随着年龄的增长&#xff0c;技术更新换代的速度会使得资深程序员难以跟上&#xff1b;而另一些人则认为&#xff0c;丰富的经…

用BSP优化3D渲染

3D渲染引擎设计者面临的最大问题之一是可见性计算&#xff1a;只必须绘制可见的墙壁和物体&#xff0c;并且必须以正确的顺序绘制它们&#xff08;应该在远处的墙壁前面绘制近墙&#xff09; 。 更重要的是&#xff0c;对于游戏等应用程序来说&#xff0c;开发能够快速渲染场景…

【python】Jupyter Notebook 修改默认路径

文章目录 一、修改前&#xff08;一&#xff09;问题&#xff08;二&#xff09;修改前的默认路径 二、修改配置文件、更改路径&#xff08;一&#xff09;找到配置文件并打开&#xff08;二&#xff09;创建目标文件夹、得到新的路径&#xff08;三&#xff09;修改配置文件 三…

Android15功能和 API 概览

Android 15 面向开发者引入了一些出色的新功能和 API。以下部分总结了这些功能&#xff0c;以帮助您开始使用相关 API。 如需查看新增、修改和移除的 API 的详细列表&#xff0c;请参阅 API 差异报告。如需详细了解新的 API&#xff0c;请访问 Android API 参考文档&#xff0…