Flutter 小技巧之通过 MediaQuery 优化 App 性能
许久没更新小技巧系列,温故知新,在两年半前的《 MediaQuery 和 build 优化你不知道的秘密》 我们聊过了在 Flutter 内 MediaQuery 对应 rebuild 机制,由于 MediaQuery 在 MaterialApp 内,并且还是一个 InheritedWidget , 所以每当你使用一个 MediaQuery.of(context) ,其实就是在向 InheritedWidget 内登记更新绑定 :

具体例子如下图所示:
- 我们在
MyHomePage使用了MediaQuery.of(context) - 然后我们跳转到
EditPage - 在
EditPage打开键盘,然后作为上一级页面的MyHomePage触发了一些列 rebuild 打印

上面的例子很好诠释了 MediaQuery.of(context) 使用不当的后果,特别是当堆栈内页面多的时候,就有很多不必要的开销,而要知道 MediaQuery 涉及 20 来参数,从各种边界到字体大小再到界面比例,可以说在 UI 适配时是经常使用的对象,特别是折叠屏场景更是必不可少,所以合理使用 MediaQuery 就非常重要。

而事实上同样代码,你只需要将 MediaQuery.of(context) 挪到页面 Scaffold 内去使用它的 ctx,就会发现第二个页面打开键盘时第一个页面不会触发 rebuild 了:

而为什么放到页面 Scaffold 内去使用 context 就好很多?这是因为 Scaffold 内通过「覆盖」MediaQuery ,让他的 body 等 child 部分在 MediaQuery.of(context) 时获取到的是 Scaffold 内的 MediaQueryData :

另外由于 Scaffold 内部也大量使用 MediaQuery ,在触发 MediaQueryData 更新时,也会触发 Scaffold 的更新, 所以其内部像 body 等参数,也会通过 widget.body 实例等方式,从而避免由于 MediaQuery 更新导致其 child 重复 rebuild 的问题 :
更多细节可见:《 MediaQuery 和 build 优化你不知道的秘密》
所以我们知道,使用 MediaQuery 拿的是哪个 context 很重要,如果用错了非 Scaffold 的 context ,那么就很容易造成不必要的性能损耗。
而不同 context 也可能让你拿到不一样的参数结果,比如各种 padding 。
但是,前面我们说到 MediaQuery 本身带有那么多参数,如果我们只是在意 size ,但是键盘弹出的时候改变的是 viewInsets ,如果这样也导致页面更新,好像也不是很合理,所以后来(3.10) Flutter 更新了 MediaQuery.propertyOf 系列方法。
比如还是一开始的代码,但是我把 MediaQuery.Of(context) 换成 MediaQuery.sizeOf(context) ,入下图所示,在弹出键盘时同样不会触发上一级的 MyHomePage 的 rebuild ,因为此时它关联的是独立的 size 参数:

事实上类似的用法在 Scaffold 内部也用到了,基本上能通过 paddingOf 、sizeOf 、viewInsetsOf 等 propertyOf 方法获取到参数的,就不要直接用 .Of(context) ,这也是 3.10 之后 MediaQuery 上针对性的性能提升:

而之所以 propertyOf 系列参数可以做到约束 MediaQueryData 更新时只触发绑定参数的能力,内部主要还是在 context 登记时,通过 aspect 单独触发 InheritedModel 实现。
每个 InheritedModel 都是一个单独的 InheritedWidget 的实现,而这样 InheritedModel 内部的 InheritedModelElement 就会记录每个子组件依赖的 aspect,从而形成一个新的独立类型映射,因此 InheritedModel 支持订阅特定模型的变化。
另外,关于 MediaQueryData.fromWindow ,在上古版本内还有 MediaQueryData.fromWindow 这样的 API ,而现在都是 MediaQueryData.fromView ,而之所以这么调整是因为:
起初 Flutter 假定了它只支持一个 Window 的场景,所以会有
SingletonFlutterWindow这样的 instance window 对象存在,同时window属性又提供了许多和窗口本身无关的功能,而这种设定在未来多窗口逻辑下会显得很另类。
所以后来开始废除单例 window ,改为 View.of(context) ,也就是可以通过 MediaQueryData.fromView(View.of(context)) 这样的方式获取 MediaQueryData ,类似的还有:
/// 3.10 之前
double dpr = WidgetsBinding.instance.window.devicePixelRatio;
Locale locale = WidgetsBinding.instance.window.locale;
double width =MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width;/// 3.10 之后
double dpr = View.of(context).devicePixelRatio;
Locale locale = View.of(context).platformDispatcher.locale;
double width =MediaQueryData.fromView(View.of(context)).size.width;
可以看到,这里的 View 内部肯定也是一个 InheritedWidget ,它将 FlutterView 通过 BuildContext 往下共享,从而提供类似上古时代 「window」 的参数能力,而通过 View.of 获取的参数:
- 当
FlutterView本身的属性值发生变化时,是不会通知绑定的context更新,这个行为类似于之前的WidgetsBinding.instance.window - 只有当
FlutterView本身发生变化时,比如context绘制到不同的FlutterView时,才会触发对应绑定的context更新
可以看到现在 View.of 这个行为考虑的是「多 FlutterView」 下的更新场景,如果在单 FlutterView 场景下,它几乎就是静态的,如果你不关心 MediaQuery 动态更新的场景,后者你更应该使用这类「静态获取」的方式。
更多可见 《一起来了解 View.of 和 PlatformDispatcher》
好了,今天的小技巧就到这里,温故知新,基本上今天的内容都是过去的片段,把它们放在一起之后,你应该就知道如何使用 MediaQuery 可以让你的 Flutter App 性能有所提升了吧?
相关文章:
Flutter 小技巧之通过 MediaQuery 优化 App 性能
许久没更新小技巧系列,温故知新,在两年半前的《 MediaQuery 和 build 优化你不知道的秘密》 我们聊过了在 Flutter 内 MediaQuery 对应 rebuild 机制,由于 MediaQuery 在 MaterialApp 内,并且还是一个 InheritedWidget ࿰…...
操作系统知识点23
1.实时操作系统的主要设计目标:在严格时间氛围内对外部请求做出反应。 2.当用户程序正在处理器上运行时,若此刻取到了一条特权指令,则处理器将停止执行该指令,并产生一个“非法操作”的事件 3.某网络监控系统中。多个被授权的用…...
【解决报错】:detected dubious ownership in repository at ‘D:/idea_code/xxx‘问题
解决报错:detected dubious ownership in repository at D:/idea_code/xxx‘问题 git config --global --add safe.directory *原因 这个错误提示表明 Git 检测到仓库的所有权存在问题,仓库的所有者与当前用户不匹配。Git 在 2.35.2 版本之后引入了一个…...
三角函数:从宇宙法则到AI革命的数学密钥
——跨越三千年的数学语言与现代科技全景透视 一、数学本质:宇宙的波动密码 1.1 拓扑学视角下的三角函数 三角函数本质是单位圆上点的坐标参数化,其数学表达可抽象为: { x cos θ ℜ ( e i θ ) y sin θ ℑ ( e i θ ) \begin…...
SpringBoot基础Kafka示例
这里将生产者和消费者放在一个应用中 使用的Boot3.4.3 引入Kafka依赖 <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId> </dependency>yml配置 spring:application:name: kafka-1#kafka…...
Spring 的三种注入方式?
1. 实例的注入方式 首先来看看 Spring 中的实例该如何注入,总结起来,无非三种: 属性注入 set 方法注入 构造方法注入 我们分别来看下。 1.1 属性注入 属性注入是大家最为常见也是使用最多的一种注入方式了,代码如下&#x…...
STM32第一天建立工程
新建一个工程 1:新建一个文件,添加文件 a:DOC工程说明 》doc说明文档 b:Libraries固件库 》cmsis内核文件 (一般这就是stm32内核文件) 》FWLIB外设文件 (这种就是stm32外设文件不全) 》start…...
记录一下返修
1.对复杂度的分析还不够; 2.融合两种指标的解释还不够,审稿人认为这两种指标存在冲突,不能同时优化,但其实我们考虑的是公平性保证整个调度周期内用户分配到了更加平均的sum-rate,而se是为了追求每个调度时刻都尽可能找到信道条件…...
搭建本地化笔记AI:用Copilot+deepseek+nomic-embed-text构建本地智能知识系统
安装Ollama https://ollama.com/ 下载模型 下载大语言模型 根据自己电脑的配置选择模型的大小 ollama run deepseek-r1:8b 下载向量处理模型 创建向量数据库时需要使用Embedding模型对文本进行向量化处理 ollama pull nomic-embed-text 查看安装的模型 ollama listNAME …...
【C语言】指针篇
目录 C 语言指针概述指针的声明和初始化声明指针初始化指针 指针的操作解引用操作指针算术运算 指针的用途动态内存分配作为函数参数 指针与数组数组名作为指针通过指针访问数组元素指针算术和数组数组作为函数参数指针数组和数组指针指针数组数组指针 函数指针函数指针的定义和…...
【蓝桥杯单片机】第十一届省赛
一、真题 二、创建工程 1.在C盘以外的盘新建文件夹,并在文件夹里面创建两个文件夹Driver 和Project 2.打开keil软件,在新建工程并选择刚刚建好的project文件夹,以准考证号命名 3.选择对应的芯片型号 4.选择否,即不创建启动文件 …...
【存储中间件】Neo4J图数据库超详细教程(一):相关介绍、特点及优势、数据模型、软件安装
文章目录 Neo4J超详细教程一、Neo4J相关介绍1.为什么需要图数据库方案1:Google方案2:Facebook 2.特点和优势3.什么是Neo4j4.Neo4j数据模型图论基础属性图模型Neo4j的构建元素 5.软件安装 个人主页:道友老李 欢迎加入社区:道友老李…...
xxl-job部署在docker-destop,实现定时发送预警信息给指定邮箱
XXL-JOB XXL-JOB是一个分布式任务调度平台(XXL是作者徐雪里姓名拼音的首字母),其核心设计目标是开发迅速、学习简单、轻量级、易扩展。 源码仓库地址:https://github.com/xuxueli/xxl-job 源码结构: 系统架构 在xxl-j…...
【QT】QScrollBar设置样式:圆角、隐藏箭头、上边距等
目录 0.简介 1.原理 2.具体代码 0.简介 环境:Ubuntu22.04、qtDesigner绘制UI 项目需要,按照UI修改滚动条样式,滚动条我使用的是QScrollBar,默认样式和修改之后的样式如下: 1.原理 2.具体代码 我是用qtDesigner绘制…...
trae中文版AI搭建完整可用的项目框架
Trae 是由字节跳动推出的 AI 原生集成开发环境(AI IDE),号称可以搭建完整项目,个人试用后体验确实比Cursor或cline更便捷,因为他多个文件关联准确率更高。 正式版的trae不支持大陆使用,不过目前已经推出了…...
多数元素——面试经典150题(力扣)
题目 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入:nums [3,2,3] 输出:3 …...
cfi网络安全 网络安全hcip
目录 RIP (路由信息协议) 算法 开销 版本 开销值的计算方式 RIPV1和RIPV2的区别 RIP的数据包 Request(请求)包 Reponse(应答)包 RIP的特征 周期更新 RIP的计时器 1,周期更新计时器 2,失效计时器 3,垃圾回收计时器 RIP的核心思…...
Banana Pi 与瑞萨电子携手共同推动开源创新:BPI-AI2N
2025年3月11日, Banana Pi 开源硬件平台很高兴宣布,与全球知名半导体解决方案供应商瑞萨电子(Renesas Electronics)正式达成技术合作关系。此次合作标志着双方将在开源技术、嵌入式系统和物联网等领域展开深度合作,为全…...
linux 命令 ls
ls 是 Linux 系统中用于列出目录内容的核心命令,几乎所有日常操作都会用到。以下是其详细用法和常见场景说明 1. 基础语法 ls [选项] [目录/文件] 不指定目录时,默认列出当前目录的内容。 可以指定文件或目录路径,支持通配符(如…...
论数组去重之高效方法
论数组去重之高效方法 数组去重的高效方法主要有 利用 Set 数据结构、利用对象/Map哈希表、排序后遍历去重 三种核心方案。其中 Set 是ES6最简单高效的方式,时间复杂度为 O(n);若需兼容性优化或处理特殊数据类型,可结合哈希表或排序实现。 分点论述: 1. 使用 Set 数据结构…...
C#-扩展方法-Linq
密封类 sealed,无法被继承 var 可以定义匿名对象 static void test1() {var t 1;t "jack";//报错,类型已经确定好了var s new{id 1,name "tom"};Console.WriteLine(s.id s.name); } 扩展方法 对现有类型做方法的扩展&am…...
【C++ STL】 容器详解:pair 学习
在 C STL(标准模板库)中,pair 是一个 简单的键值对数据结构,用于存储 两个相关联的值,将两个值组合成一个单元,可以是相同或不同类型。它常用于 返回多个值、存储映射关系、排序 等场景。 1. pair 的基本特…...
Go红队开发—web网络编程
文章目录 web网络编程Req快速请求 调试DevModeDebugLogTraceInfo瓶颈分析 控制请求与响应控制请求的字段内容控制调试打印的内容分开dump请求与响应部分请求体设置 作用范围级别设置参数查询URL 路径参数表单请求设置请求头设置 判断响应状态码解析数据SetSuccessResultgjson响…...
libwebsockets实现异步websocket客户端,服务端异常断开可重连
libwebsockets websocket客户端基本流程网上都有,我只额外优化了重连机制。 在服务器异常断开时不触发LWS_CALLBACK_CLOSED或LWS_CALLBACK_CLIENT_CONNECTION_ERROR,导致无法自动重连 通过定时检查链接是否可写入判断链接是否有效 // 判断wsi是否可用if …...
轻量级模块化前端框架:快速构建强大的Web界面
轻量级模块化前端框架:快速构建强大的Web界面 在当今快节奏的Web开发环境中,选择一个高效且灵活的前端框架至关重要。UIkit 是一个轻量级的模块化前端框架,旨在帮助开发者快速构建功能强大且响应迅速的Web界面。 UIkit提供了丰富的组件和工…...
qt+opengl 播放yuv视频
一、实现效果 二、pro文件 Qt widgets opengl 三、主要代码 #include "glwidget.h"GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent) {connect(&m_timer, &QTimer::timeout, this,[&](){this->update();});m_timer.start(1000/33); }v…...
UI自动化:poium测试库
以下是关于 poium 测试库 的详细介绍,涵盖其核心功能、使用方法及与原生 Selenium 的对比,帮助快速掌握这一工具: 1. poium 简介 定位:基于 Selenium 的 Page Object 模式增强库,专注于简化元素定位和页面操作。 核心…...
树莓集团落子海南,如何重构数字产业生态体系
树莓集团在海南的布局,是其整体商业战略中的关键一环。这背后,是对政策机遇、产业协同、以及区域优势的深度考量。 政策机遇 海南自贸港建设带来前所未有的政策红利,包括贸易、投资、资金等方面的自由便利。树莓集团紧抓这一机遇࿰…...
5G基本概念
作者:私语茶馆 1. 5G应用场景概述 1.1.5G应用场景 ITU域2015年定义了三大应用场景:eMBB(增强型移动宽带)、uRLLC(低时延高可靠通信)、mMTC(海量物联网通信); emBB:Enhanced Mobile Broadband ,移动互联网应用,是4G MBB(移动宽带)的升级,主要侧重于网络速率、带…...
PH热榜 | 2025-03-12
1. Fluently 标语:开始说英语,就像说你的母语一样流利。 介绍:想象一下,有一个像人类一样的英语教练,全天候在线、价格却便宜15倍。这就是 Fluently 🚀 纠正你的错误,提升你的词汇量、发音和语…...
