elementui查询界面-Flutter调优-深入MediaQuery导致界面重建原因及解决方案

2023-08-26 0 6,007 百度已收录

前言

我们可以使用 MediaQuery.of(context) 方法来获取一些设备和系统相关的信息,比如状态栏的高度、当前是否处于深色模式等。使用起来相当方便,但是我们也必须注意可能的页面重建问题。 本文将介绍一个典型案例,并深入源码解释重建的原因,最后介绍几种防止重建的方法。

典型

以快递应用中的快递查收场景为例。 首页使用MediaQuery.of(context).padding.top获取状态栏的高度。 当用户点击“查询快递”按钮时,会跳转到查询快递界面。 在快递查询界面,用户输入单号即可查询。

当调用首页的build方法时,会输出我们提前添加的日志。 我们发现,当查询快递界面的按钮弹出时,首页的build方法被多次调用:

主界面的构建代码如下:

源代码探索

由于主界面在build方法中使用了MediaQuery.of(context),导致鼠标弹出/隐藏时要进行重建操作,所以我们先看一下MediaQuery类。

媒体查询

它继承自InheritedWidget,并且不会重绘createElement方法本身。 从flutter三棵树来看,对应的Element是InheritedElement。 有两个属性,data和child,我们可以从data中获取一些设备/系统相关的属性。

还有两个比较重要的方法:

fromWindow(key: Key, child: Widget)

该方法直接返回_MediaQueryFromWindow对象,后面会详细介绍。

的(上下文:BuildContext)

该方法调用了dependOnInheritedWidgetOfExactType,接下来我们详细分析其背后的调用过程。

MediaQuery.of(context)调用流程

输入参数是上下文。 在这个例子中,主界面是StatelessWidget,所以这里的上下文是StatelessElement。 整体调用流程如下:

dependentOnInheritedWidgetOfExactType

查询_inheritedWidgets列表中是否存在MediaQuery类型的InheritedElement。 从三棵树来看,就是从当前节点向下搜索,找到最近的MediaQuery控件。 如果找到了,就调用dependOnInheritedElement方法(一般情况下是一定能找到的,下面我会详细介绍)。

依赖于继承元素

该方法负责保存找到的InheritedElement(即MediaQuery对应的Element)并调用InheritedElement#updateDependency方法。

更新依赖关系

设置依赖关系

最后两种方法非常简单。 它们的作用就是将首页对应的StatelessElement存储在MediaQuery对应的InheritedElement#_dependents中。

研究了MediaQuery.of(context)背后的原理,我们可以知道,通过调用of方法elementui查询界面,主界面对应的Element和MediaQuery建立了绑定关系,而MediaQuery对应的InheritedElement则存储了该Element对MediaQuery的引用。主界面。

重建起点

在介绍dependOnInheritedWidgetOfExactType方法时,我们提到:从当前节点到父节点查找,一般情况下,一定能找到MediaQuery控件。 这是因为将在 WidgetsApp 中手动为我们创建根 MediaQuery。

在main方法中,无论是使用CupertinoApp还是MaterialApp,最后都会在内部创建WidgetsApp。 我们直接看_WidgetsAppState#build方法中的一段代码:

首先会检测到 Widget.useInheritedMediaQuery,该属性默认为 false。 如果创建MaterialApp/CupertinoApp时没有设置useInheritedMediaQuery属性,或者设置该属性为null,但是找不到MediaQueryData,那么这里会调用MediaQuery.fromWindow方法。

当上面介绍 MediaQuery#fromWindow 时,我们知道它将创建 _MediaQueryFromWindow 控件。

_MediaQueryFromWindow的代码不是很多。 我已经粘贴了与本文相关的所有代码。 你可以自己看一下。 代码如上图所示。

build方法中创建MediaQuery控件,并实现didChangeMetrics方法。 当手机旋转、键盘弹出/隐藏时会调用该方法。 didChangeMetrics 内部调用了 setSate,这会导致再次调用 build 方法。

通过flutter的三棵树原理我们可以知道,上述“build方法被重新调用”涉及到MediaQueryFromWindow对应的Element的updateChild方法。 我们简单看一下updateChild的内部处理规则:

对于MediaQueryFromWindow,每次都会创建一个新的MediaQuery Widget。 根据Element#updateChild的源码(不是本文的重点,我不会详细分析它的源码),最终会调用MediaQuery对应的Element的更新技术。

经过一系列的跳转,最终会调用以下两个核心技术:

上面介绍的 MediaQuery.of(context) 方法最终会将输入参数 Context 放入 _dependents 变量中,这里会遍历map,调用各个Context的didChangeDependecies方法。 didChangeDependecies 会将 Context 设置为脏状态,当下一帧临近时,就会重绘,并调用这个 Context 的 build 方法。

这样,问题就解决了elementui查询界面,当按钮弹出/隐藏时,通过重建的激励就能找到快递主页!

整体重建调用流程如下。 如果有兴趣,可以结合这个调用流程图来看看源码:

避免重建的方法

研究了源码之后,解决方案就变得非常简单了。

总结

当app界面变得更加复杂时,我们就不得不考虑优化界面性能。 本文描述的案例在开发中很常见。 如果不了解MediaQuery.of的机制,可能会导致使用该方法的界面大量重绘,导致页面卡顿、帧率升高。 我们详细分析了其背后的源码逻辑并介绍了解决方案,希望能为您的调优工作提供一些帮助。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 elementui elementui查询界面-Flutter调优-深入MediaQuery导致界面重建原因及解决方案 https://www.wkzy.net/game/159298.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务