了解并解决 Flutter 中的灰屏问题

生产中的 flutter 应用程序中的灰屏是一种通用占位符,当框架遇到问题无法渲染预期用户界面时就会显示。是的,所以基本上是出现问题时的后备指示器。

有趣的是,这只出现在发布模式下。在任何其他模式下运行都会显示红色错误屏幕,并说明导致错误的原因。 (检查此处以了解各种类型的构建模式。)此类错误的常见原因是:

  • 未处理的异常:这些是运行时发生的错误,未使用 try-catch 块捕获。
  • 渲染错误:这些是渲染布局时引起的问题,例如,在 ColumnRowFlex 小部件外部使用 Expanded 时引起的问题。

以下是可能导致灰屏的代码示例:

class HomeView extends HookWidget {const HomeView({super.key});Widget build(BuildContext context) {const widget = null;return Scaffold(appBar: AppBar(title: Text('Gallery',style: Theme.of(context).textTheme.headlineLarge,),),body: widget!,);}
}

在这里,我们犯了一个明显的错误,在我们知道的 null 小部件上使用了 bang 运算符(!),这导致在非发布模式下出现红屏,在发布模式下出现灰屏。

需要注意的是,我们不建议在不更新的情况下将部件明确设置为空值,空值错误是一个常见错误,而上述操作是重现该错误的简单方法。

调试模式下的红色错误屏幕(左)和发布模式下的灰色屏幕(右)的图像

自定义错误屏幕

为了显示更用户友好的消息而不是灰屏,我们将策略性地在 main 函数中放置一行代码。该行充当预防措施,确保每当发生未处理的异常时都会显示自定义错误屏幕。


void main() {ErrorWidget.builder = (_) => const AppErrorWidget(); // This line does the magic!runApp(MyApp());
}

有条件的红屏(可选):

也许您希望在开发过程中看到默认的红色错误屏幕以进行调试。您可以通过将 ErrorWidget.builder 赋值包装在检查当前构建模式的 if 语句中来实现此目的:

void main() {if (kReleaseMode) ErrorWidget.builder = (_) => const AppErrorWidget();runApp(MyApp());
}

下一步涉及创建 AppErrorWidget 本身的内容。该小部件将确定发生未处理的异常时用户看到的内容。

class AppErrorWidget extends StatelessWidget {const AppErrorWidget({super.key});Widget build(BuildContext context) {return const Material(color: Colors.white,child: Padding(padding: EdgeInsets.all(24),child: Column(mainAxisAlignment: MainAxisAlignment.center,mainAxisSize: MainAxisSize.min,children: [Icon(Icons.warning,size: 200,color: Colors.amber,),SizedBox(height: 48),Text('So... something funny happened',textAlign: TextAlign.center,style: TextStyle(fontSize: 24,fontWeight: FontWeight.bold,),),SizedBox(height: 16),Text('This error is crazy large it covers your whole screen. But no worries'' though, we\'re working to fix it.',textAlign: TextAlign.center,style: TextStyle(fontSize: 16,),),],),),);}
}

AppErrorWidget 小部件的结果显示

虽然鼓励自定义应用程序的体验,但 ErrorWidget.builder 上的 Flutter 文档提醒我们,调用错误小部件时视图处于不稳定状态。构建(可能还有布局)期间的异常会使系统处于脆弱状态。为了最大限度地减少进一步的问题,返回的小部件应该做最少的工作。 LeafRenderObjectWidget (如默认的 RenderErrorBox )非常适合处理意外约束。

ErrorWidget.builder 的幕后花絮

现在我们知道,当渲染预期 UI 的过程中发生错误时, ErrorWidget.builder 就会被调用,但是这到底是如何实现的呢?

如果我们深入研究 Flutter 的框架,我们会在构建或重建小部件时看到一个名为 _updateChild() 的方法。

void _updateChild() {try {final Widget child = (widget as _RawView).builder(this, _effectivePipelineOwner);_child = updateChild(_child, child, null);} catch (e, stack) {final FlutterErrorDetails details = FlutterErrorDetails(exception: e,stack: stack,library: 'widgets library',context: ErrorDescription('building $this'),informationCollector: !kDebugMode ? null : () => <DiagnosticsNode>[DiagnosticsDebugCreator(DebugCreator(this)),],);FlutterError.reportError(details);final Widget error = ErrorWidget.builder(details);_child = updateChild(null, error, slot);}
}

我们可以看到 ErrorWidget.builder 属性用于根据提供的 FlutterErrorDetails 检索自定义错误小部件;然后更新 _child 变量以显示自定义错误小部件而不是原始子小部件。

提升开发者体验

定制向用户呈现错误的方式是改善用户体验的关键一步。虽然 ErrorWidget.builder 帮助我们在出现错误时管理用户体验,但它并没有为生产环境中的开发人员提供有价值的见解。本地调试不再是一种选择,那么我们如何及时了解用户设备上发生的错误呢?

这就是我们利用 FlutterError.onError 回调的力量的地方。让我们看看这是如何完成的:

void main() {if (kReleaseMode) ErrorWidget.builder = (_) => const AppErrorWidget();FlutterError.onError = (details) {FlutterError.dumpErrorToConsole(details);if (!kReleaseMode) return;// 发送到您的 crashlytics 服务...};runApp(MyApp());
}

我们添加了一行新代码,它将新的回调函数分配给 FlutterError.onError 属性。每当使用 FlutterError.reportError 报告错误时都会调用此回调。

在回调内部, FlutterError.dumpErrorToConsole(details) 通过将错误详细信息转储到控制台来帮助我们了解幕后情况。这对于在部署或分阶段部署期间可能存在对用户设备的访问受限的调试目的非常有用。

最后的注释行 ( // 发送到您的 crashlytics 服务... ) 强调了这种方法的真正威力。在这里,您可以集成您选择的错误报告服务(例如 Crashlytics)以发送详细的错误报告以供分析。

注意:此行包含在 if 语句中,以确保它仅在调试或分析模式下执行 ( !kReleaseMode )。

避免灰屏的最佳错误处理实践

我们已经了解了导致灰屏的原因以及出现灰屏时如何更好地处理它;我们还应该介绍的一件事是,作为开发人员可以采取哪些措施来避免出现灰屏。其中一些是:

  • 拥抱 try-catch :将关键代码部分包装在 try-catch 块内。这允许您捕获潜在的异常并提供优雅的回退机制。
  • 少用 Bang 运算符 (!):bang 运算符 (!) 是 null 断言检查的快捷方式,但如果用于不确定是否为非 null 的值,可能会导致意外错误。更多地使用条件表达式 (??) 或 null 感知访问运算符 (?.)。
  • 彻底的应用程序测试:结合使用单元、小部件、集成和手动测试来帮助在问题出现在生产中之前识别和解决问题。
  • 尊重 Widget 约束:Flutter 中的每个 Widget 都有局限性和预期的使用模式;避免在其限制之外使用它们,例如在可滚动视图中使用 Spacer

结论:拥抱不可避免的事情

错误处理是任何编写良好的 Flutter 应用程序的重要组成部分。当您努力编写干净的代码并预测潜在问题时,异常情况必然会发生。通过实施 ErrorWidget.builder ,您可以确保即使发生意外情况,您的用户也会看到清晰且内容丰富的消息,而不是令人困惑的灰屏,并且通过 FlutterError.onError 您可以确保您记录这些意外错误,并且可以更轻松地调试和修复这些错误。

请记住,即使面对不可预见的障碍,一点准备对于保持积极的用户和开发人员体验也大有帮助。


原文:https://medium.com/@LordChris/understanding-and-addressing-the-grey-screen-in-flutter-5e72c31f408f

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

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

相关文章

Oracle 数据库表和视图 的操作

1. 命令方式操作数据库&#xff08;采用SQL*Plus&#xff09; 1.1 创建表 1.1.1 基本语法格式 CREATE TABLE[<用户方案名>]<表名> (<列名1> <数据类型> [DEFAULT <默认值>] [<列约束>]<列名2> <数据类型> [DEFAULT <默认…

【Python 基本变量教程及案列】

Python 基本变量教学 在Python中&#xff0c;变量是一种用来存储数据的标识符。变量可以存储各种数据类型&#xff0c;包括整数、浮点数、字符串、布尔值、列表、元组、字典等。以下是Python基本变量的详细介绍及案例示范。 1. 变量声明与赋值 在Python中&#xff0c;声明变…

Trying to access array offset on value of type null

主要原因是版本7.4以后PHP解析器会对null类型的下标访问直接报错 背景&#xff1a; laravel框架 同时使用了扩展A和扩展B 扩展A要求 php>7.4,同时扩展B的对null类型的下标访问不兼容php7.4 修改扩展B不太现实&#xff0c;毕竟扩展B中有太多的对null类型的下标访问。 解决…

忘记word文档加密密码要如何破解word文档密码呢?

如今工作中已离不开各类办公软件&#xff0c;办公软件中Word几乎是天天被用到&#xff0c;为了保护数据&#xff0c;用户会为Word文档设置密码&#xff0c;但时间久了不记得密码了就非常麻烦。Word文档加密忘记密码怎样能打开&#xff1f;下面来看详细介绍吧&#xff01; 一、使…

志愿服务管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;基础数据管理&#xff0c;广场论坛管理&#xff0c;志愿活动管理&#xff0c;活动报名管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;志愿活动&a…

YOLOv10项目-服务器上运行

1、前言 2、运行YOLOv10代码流程&#xff08;超详细&#xff09; &#xff08;3&#xff09;根据下面步骤安装&#xff1a; &#xff08;4&#xff09;数据集和其他配置 &#xff08;5&#xff09;测试训练&#xff08;很详细&#xff09; 1、前言 由于一些事情&#xff0…

PLSQL、Oracle以及客户端远程连接服务器笔记(仅供参考)

1.PLSQL参考链接&#xff1a; 全网最全最细的PLSQL下载、安装、配置、使用指南、问题解答&#xff0c;相关问题已汇总-CSDN博客文章浏览阅读2.9w次&#xff0c;点赞98次&#xff0c;收藏447次。双击之后&#xff0c;这里选择安装目录&#xff0c;你安装目录选的哪里&#xff0…

React 事件函数传播及捕获

事件传播 事件处理函数将捕获任何来自子组件的事件。事件会沿着树向上“冒泡”或“传播”&#xff1a;它从事件发生的地方开始&#xff0c;然后沿着树向上传播。 在 React 中所有事件都会传播&#xff0c;除了 onScroll&#xff0c;它仅适用于你附加到的 JSX 标签。 <div cl…

C++240617

2、升级优化自己应用程序的登录界面。 要求&#xff1a; 1. qss实现 2. 需要有图层的叠加 &#xff08;QFrame&#xff09; 3. 设置纯净窗口后&#xff0c;有关闭等窗口功能。 4. 如果账号密码正确&#xff0c;则实现…

mysql如何创建并执行事件?

在 MySQL 中,事件调度器允许您在指定的时间间隔执行 SQL 语句。这类似于操作系统中的计划任务(如 cron 作业)。 前提条件 确保您的 MySQL 服务器已启用事件调度器。可以通过以下命令检查并启用: SHOW VARIABLES LIKE event_scheduler;如果返回的值是 OFF,可以通过以下命…

【算法实战】每日一题:18.3 ST表 - 给定一个整数序列和一系列区间查询,求每个查询区间内所有整数的最大公约数。

题目 给定一个整数序列和一系列区间查询&#xff0c;求每个查询区间内所有整数的最大公约数。 思路 上一节我们详细的学完ST表后&#xff0c;这里就比较好算了&#xff0c;直接把ST表的板子换一下增加一个GCD即可 解决方案 import mathdef gcd(a, b):if b 0:return aretu…

编译期间生成代码(Lombok原理)

通过在编译期间&#xff0c;修改Java的AST(Abstract Syntax Tree)树&#xff0c;可以往类中&#xff0c;添加/修改&#xff08;覆盖&#xff09;方法、属性等。 现在比较常见的三方依赖例子有&#xff1a;Lobbok的Data可以生成get、set方法&#xff0c;Sl4j2可以生成静态常量l…

Java图形用户界面设计的布局管理器

LayoutManager布局管理器 前言一、布局管理器的背景简介 二、FlowLayout构造方法参数说明代码演示AWTSwing 三、BorderLayout布局管理器注意点构造方法代码演示AWT示例一示例二 Swing 四、GridLayout简介构造方法代码示例AWTSwing 五、GridBagLayoutGridBagConstraints APIGrid…

Redis 数据持久化策略和数据过期策略

01- 你们项目中哪里用到了Redis ? 在我们的项目中很多地方都用到了Redis , Redis在我们的项目中主要有三个作用 : 使用Redis做热点数据缓存/接口数据缓存 使用Redis存储一些业务数据 , 例如 : 验证码 , 用户信息 , 用户行为数据 , 数据计算结果 , 排行榜数据等 使用Redis实…

Java项目常用包的分层和作用

一个好的Java项目要有好的分层&#xff0c;不仅简洁明了&#xff0c;而且降低代码的耦合度&#xff0c;方便维护和升级。 web层 在Java Web应用程序中&#xff0c;Web层通常指的是处理HTTP请求和响应的层次&#xff0c;它直接与客户端&#xff08;通常是Web浏览器&#xff09…

【一】【QT开发应用】QT开发环境配置,安装QT应用

下载QT软件 点击网址链接&#xff0c;QT下载网址 下载vsaddin插件 点击网址链接&#xff0c;QT下载网址 根据自己的vs版本下载对应的文件. 安装QT 用命令行打开安装程序 找到直接路径, D:\Software\QT\qt-unified-windows-x86-4.3.0-1-online.exe 利用WindowsPowe…

Gauss200使用分享

登录、授权控制 解锁账户 su - omm gsql -d db_rdb -p 8000 -ralter user ado_user account unlock; alter user sig_qry_rpt account unlock;参数控制 && 优化参考 只读模式解锁 su - omm gs_guc reload -Z coordinator -Z datanode -N all -I all -c "defau…

Python自动化测试面试题精选(一)

今天大家介绍一些Python自动化测试中常见的面试题&#xff0c;涵盖了Python基础、测试框架、测试工具、测试方法等方面的内容&#xff0c;希望能够帮助你提升自己的水平和信心。 项目相关 什么项目适合做自动化测试&#xff1f; 答&#xff1a;一般来说&#xff0c;适合做自…

文档项目:攻坚克难

鉴于交流离心机存在的缺点&#xff1a;转速相对偏差、稳定精度不够高&#xff1b;带负载能力受外界扰动后&#xff0c;波动较大&#xff1b;寿命短&#xff0c;研究所各相关部门成立组成技术攻关团队&#xff0c;齐心协力&#xff0c;攻坚克难&#xff0c;在摸索中突破创新&…

坚持刷题|合并有序链表

文章目录 题目思考代码实现迭代递归 扩展实现k个有序链表合并方法一方法二 PriorityQueue基本操作Java示例注意事项 Hello&#xff0c;大家好&#xff0c;我是阿月。坚持刷题&#xff0c;老年痴呆追不上我&#xff0c;消失了一段时间&#xff0c;我又回来刷题啦&#xff0c;今天…