文章目录

  • Flutter页面更新流程剖析
    • 更新流程
    • 渲染过程
    • 视频课程

博主相关文章列表
Flutter 框架实现原理
Flutter 框架层启动源码剖析
Flutter 页面更新流程剖析
Flutter 事件处理源码剖析
Flutter 路由源码剖析
Flutter 安卓平台源码剖析(一)
Flutter 自定义控件之RenderObject

Flutter页面更新流程剖析

更新流程

当我们需要更新页面时,会调用setState方法,这里我们就以之为突破口,研究一下页面更新的流程。

flutter\lib\src\widgets\framework.dart

/// [State]void setState(VoidCallback fn) {final dynamic result = fn() as dynamic;_element.markNeedsBuild();
}

删除断言后,其实只有两行代码,首先是执行了传入的闭包,接着调用markNeedsBuild()方法

/// [Element]void markNeedsBuild() {if (!_active)return;if (dirty)return;// 将当前的Element标记为_dirty,表示需要重建_dirty = true;// 将当前元素添加到 dirty 元素列表中,这样当[WidgetsBinding.drawFrame]调用[buildScope]时它就会被重建owner.scheduleBuildFor(this);
}

这里调用了BuildOwner中的scheduleBuildFor方法

/// [BuildOwner]void scheduleBuildFor(Element element) {if (element._inDirtyList) {_dirtyElementsNeedsResorting = true;return;}if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {_scheduledFlushDirtyElements = true;// 执行_handleBuildScheduled回调onBuildScheduled();}// 添加到 dirty 元素列表_dirtyElements.add(element);element._inDirtyList = true;
}

在《框架启动源码剖析》一文中,我们剖析过WidgetsBinding的初始化

/// [WidgetsBinding]void initInstances() {super.initInstances();_instance = this;_buildOwner = BuildOwner();buildOwner.onBuildScheduled = _handleBuildScheduled;/// ......省略......
}void _handleBuildScheduled() {// 如果我们正在构建dirty元素,则更改不应触发新的帧ensureVisualUpdate();
}// 如果此对象当前没有产生一个帧,则使用 scheduleFrame 调度一个新的帧
void ensureVisualUpdate() {switch (schedulerPhase) {case SchedulerPhase.idle:case SchedulerPhase.postFrameCallbacks:scheduleFrame();return;case SchedulerPhase.transientCallbacks:case SchedulerPhase.midFrameMicrotasks:case SchedulerPhase.persistentCallbacks:return;}
}

schedulerPhase的初始值是SchedulerPhase.idle,上面的分支执行scheduleFrame

/// [SchedulerBinding]void scheduleFrame() {// 当应用在前台可见时,_framesEnabled的值为true// 这里如果App切到后台,直接返回if (_hasScheduledFrame || !framesEnabled)return;ensureFrameCallbacksRegistered();// 执行引擎中的调度方法window.scheduleFrame();_hasScheduledFrame = true;
}void ensureFrameCallbacksRegistered() {window.onBeginFrame ??= _handleBeginFrame;window.onDrawFrame ??= _handleDrawFrame;
}

这里的scheduleFrame方法是一个引擎中的native方法,由C++实现,类似Java的JNI方法。官方对该方法做了解释

请求在下一个适当的机会调用onBeginFrameonDrawFrame回调

void scheduleFrame() native 'Window_scheduleFrame';

这里就不跟踪C++中的具体实现了,依照给出的解释,我们查看onBeginFrameonDrawFrame回调

/// [SchedulerBinding]void _handleBeginFrame(Duration rawTimeStamp) {if (_warmUpFrame) {_ignoreNextEngineDrawFrame = true;return;}handleBeginFrame(rawTimeStamp);
}void _handleDrawFrame() {if (_ignoreNextEngineDrawFrame) {_ignoreNextEngineDrawFrame = false;return;}handleDrawFrame();
}

到这里,正好对应上了我们在《框架启动源码剖析》渲染部分剖析的逻辑,关于handleDrawFrame的后续调用,请 跳转前文,这里直接查看我们关注的逻辑,主要在buildOwnerbuildScope方法中

/// [WidgetsBinding]void drawFrame() {// ......省略......try {if (renderViewElement != null)// 将被标记为dirty的Element进行rebuild()buildOwner.buildScope(renderViewElement);// 调用父类的drawFrame,这里实际上调用的是RendererBinding中的drawFrame()方法super.drawFrame();// 通过卸载任何不再活动的元素来完成元素构建过程buildOwner.finalizeTree();}// ......省略......
}
/// [BuildOwner]void buildScope(Element context, [ VoidCallback callback ]) {if (callback == null && _dirtyElements.isEmpty)return;Timeline.startSync('Build', arguments: timelineWhitelistArguments);try {_scheduledFlushDirtyElements = true;if (callback != null) {Element debugPreviousBuildTarget;_dirtyElementsNeedsResorting = false;try {callback();} finally {}}// 将dirty元素列表进行了排序_dirtyElements.sort(Element._sort);_dirtyElementsNeedsResorting = false;int dirtyCount = _dirtyElements.length;int index = 0;while (index < dirtyCount) {try {// 调用元素的rebuild_dirtyElements[index].rebuild();} catch (e, stack) {}index += 1;if (dirtyCount < _dirtyElements.length || _dirtyElementsNeedsResorting) {_dirtyElements.sort(Element._sort);_dirtyElementsNeedsResorting = false;dirtyCount = _dirtyElements.length;while (index > 0 && _dirtyElements[index - 1].dirty) {index -= 1;}}}} finally {for (final Element element in _dirtyElements) {element._inDirtyList = false;}_dirtyElements.clear();_scheduledFlushDirtyElements = false;_dirtyElementsNeedsResorting = null;Timeline.finishSync();}
}
/// [Element]void rebuild() {if (!_active || !_dirty)return;// 执行重建performRebuild();
}

这里performRebuild()是在其子类ComponentElement中实现的

/// [ComponentElement]void performRebuild() {if (!kReleaseMode && debugProfileBuildsEnabled)Timeline.startSync('${widget.runtimeType}',  arguments: timelineWhitelistArguments);Widget built;try {// 调用与该元素关联的Widget的build方法,重建控件树built = build();debugWidgetBuilderValue(widget, built);} catch (e, stack) {} finally {// 我们将元素标记为clean的时间延迟到调用build()之后,这样在build()期间尝试markNeedsBuild()就会被忽略_dirty = false;}try {// 更新元素树_child = updateChild(_child, built, slot);} catch (e, stack) {}if (!kReleaseMode && debugProfileBuildsEnabled)Timeline.finishSync();
}

这里元素树的更新逻辑,都在updateChild方法中,前面已经分析过,参见《框架启动源码剖析》

我们还可以看一下build()方法的具体实现,不同的Element,其实现不同

/// StatelessWidget对应的Element
class StatelessElement extends ComponentElement {StatelessElement(StatelessWidget widget) : super(widget);@overrideStatelessWidget get widget => super.widget as StatelessWidget;// build中的context参数实际上就是Widget对应的Element对象@overrideWidget build() => widget.build(this);@overridevoid update(StatelessWidget newWidget) {super.update(newWidget);assert(widget == newWidget);_dirty = true;rebuild();}
}
/// StatefulWidget对应的Element
class StatefulElement extends ComponentElement {StatefulElement(StatefulWidget widget): _state = widget.createState(),super(widget) {_state._element = this;_state._widget = widget;}@overrideWidget build() => _state.build(this);State<StatefulWidget> get state => _state;State<StatefulWidget> _state;// ......省略......
}

渲染过程

当需要更新页面的时候,由应用上层通知到Engine,Engine会等到下个Vsync信号到达的时候,去通知Framework上层,然后Framework会进行Animation, BuildLayoutCompositingPaint,最后生成layer提交给Engine。Engine会把layer进行组合,生成纹理,最后通过OpenGl接口提交数据给GPU, GPU经过处理后在显示器上面显示

视频课程

如需要获取完整的Flutter全栈式开发课程,请 点击跳转

Flutter 页面更新流程剖析相关推荐

  1. 【Flutter】Flutter 页面生命周期 ( 初始化期 | createState | initState | 更新期 | build | 销毁期 | dispose)

    文章目录 一.Flutter 页面生命周期 1.StatelessWidget 组件生命周期函数 2.StatefulWidget 组件生命周期函数 二.StatefulWidget 组件生命周期 1 ...

  2. Flutter页面不流畅,难道是使用姿势有问题?

    作者|檀婷婷(三莅) 出品|阿里巴巴新零售淘系技术部 背景 高性能高流畅度一直是Flutter团队宣传的一大亮点,也是当初闲鱼选择Flutter的重要因素之一,但是随着复杂业务的应用落地,通过Flut ...

  3. 【Flutter】Flutter 混合开发 ( 关联 Android 工程与 Flutter 工程 | 安卓页面中嵌入 Flutter 页面 | 安卓中启动 Flutter 页面 )

    文章目录 前言 一.创建 Android 项目 二.关联 Android 工程与 Flutter Module 工程 1.配置 Flutter Module工程 2.配置 build.gradle 3 ...

  4. 【Flutter】Animation 动画 ( Flutter 动画基本流程 | 创建动画控制器 | 创建动画 | 设置值监听器 | 设置状态监听器 | 布局中使用动画值 | 动画运行 )

    文章目录 一.创建动画控制器 二.创建动画 三.设置值监听器 四.设置状态监听器 五.布局中使用动画值 六.动画运行 七.完整代码示例 八.相关资源 Flutter 动画基本流程 : ① 创建动画控制 ...

  5. Lerna 运行流程剖析

    大家好,我是若川.持续组织了6个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列& ...

  6. Flutter Plugin开发流程

    这篇文章主要介绍了Flutter Plugin开发流程,包括如何利用Android Studio开发以及发布等. 本文主要给大家介绍如何开发Flutter Plugin中Android的部分.有关Fl ...

  7. NSX控制平面和静态路由更新流程2

    在上一篇里,我们介绍了NSX控制平面的组件,包括NSX Controller集群.DLR-CVM控制虚拟机和很容易被忽略的netcpa. 通过一个简单的实验,我们一同验证了在没有DLR-CVM的前提下 ...

  8. 沃尔沃车载电脑怎么升级鸿蒙,沃尔沃汽车导航地图自主更新流程

    沃尔沃汽车导航地图自主更新流程 2021-01-24 23:16:31 104点赞 66收藏 29评论 自己车上的沃尔沃自带地图已经好久没更新了,趁着这次沃尔沃地图最新版放出,给自己的车更新了一下,话 ...

  9. Spring Security Oauth2 单点登录案例实现和执行流程剖析

    我已经试过了 教程很完美 Spring Security Oauth2 OAuth是一个关于授权的开放网络标准,在全世界得到的广泛的应用,目前是2.0的版本.OAuth2在"客户端" ...

最新文章

  1. [JS] undefined、null、ReferenceError的区别、变量作用域问题
  2. 卫星图像中的车辆分析--A Large Contextual Dataset for Classification, Detection and Counting of Cars
  3. C语言进阶--Day2
  4. 9.1 图像处理的基本概念(图像读入、图像信息查询、图像显示和图像存储)
  5. 图片懒加载原理-实例二
  6. hadoop集群环境搭建
  7. python 保存网页到印象笔记_如何将网页内容保存到印象笔记?
  8. RTSP、RTMP、HTTP协议区别
  9. 总结一下目标检测与跟踪
  10. 【JVM学习笔记一】JVM内存分布
  11. STM-1和SDH的关系
  12. html字体样式美化,css美化文字做法详解总结
  13. Python3:私有成员
  14. java解压rar5 兼容rar4(改bug)
  15. 电脑录音,教你电脑怎么录音
  16. 【Python】输出字母在字符串中位置索引 (20 分)
  17. java插件相对布局,C#Winform中控件的布局思想
  18. 今日科技联播:微软联合创始人之一保罗·艾伦去世;锤子否认分公司解散传闻...
  19. 文档管理系统 LogicalDOC
  20. 日媒:唏嘘 美国雅虎自毁前程的3个误判

热门文章

  1. Java开发 - Redis初体验
  2. 基于双月数据集单层感知机_python
  3. 面试题(十三).NET
  4. 企业级BOM项目建设概况
  5. 网站服务器端口扫描,服务器端口扫描工具
  6. 设计模式【2.2】-- 工厂模式怎么演变成抽象工厂模式?
  7. 单片机红绿灯加强版(kile仿真程序和protues硬件仿真)
  8. 3d效果技术java,java3D技术展示
  9. ChatGLM-6B 安装试用
  10. 放假在家/异地/无法使用学校局域网-如何快速登录知网/web of science等学术平台