Flutter的setState更新原理和流程

本文来自整理和简化

调用 setState()必须是没有调用过 dispose()方法,不然出错,可通过mounted属性来判断调用此方法是否合法。

if (mounted) { setState(() {}); }


清晰的看到在framework.dart内setstate方法除了一些条件判断就是:

_element.markNeedsBuild(); 

那我们看看markNeedsBuild。

Element 类 markNeedsBuild方法

 void markNeedsBuild() { assert(_debugLifecycleState != _ElementLifecycle.defunct); if (!_active) return;//返回 ... if (dirty) return; _dirty = true; //调用scheduleBuildFor方法 owner.scheduleBuildFor(this); } 

将 element 元素标记为“脏”,并把它添加到全局的“脏”链表里,以便在下一帧更新信号时更新.

  • 这里的“ ”链表是待更新的链表,更新过后就不“脏”了。
  • 由于一帧做两次更新有点低效,所以在_active=false 的时候直接返回。

那我们看看本方法最后调用的scheduleBuildFor方法。

BuildOwner 类 scheduleBuildFor方法

BuildOwner类是widget framework的管理类,它跟踪那些需要重新构建的 widget。

void scheduleBuildFor(Element element) { ... if (element._inDirtyList) { ... _dirtyElementsNeedsResorting = true; return; } if (!_scheduledFlushDirtyElements && onBuildScheduled != null) { _scheduledFlushDirtyElements = true; onBuildScheduled();//回调 } _dirtyElements.add(element);//把element加入脏元素链表 element._inDirtyList = true; assert(() { if (debugPrintScheduleBuildForStacks) debugPrint('...dirty list is now: $_dirtyElements'); return true; }()); } 

把一个 element 添加到 _dirtyElements 链表,以便当WidgetsBinding.drawFrame中调用 buildScope 的时候能够重构 element。onBuildScheduled()是一个 BuildOwner 的回调。

onBuildScheduled回调在WidgetsBinding的initInstances里初始化。

mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {  void initInstances() { super.initInstances(); _instance = this; // 这里 buildOwner.onBuildScheduled = _handleBuildScheduled; window.onLocaleChanged = handleLocaleChanged;window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged; SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation); SystemChannels.system.setMessageHandler(_handleSystemMessage); FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator); } } 

我们可以看到buildOwner.onBuildScheduled回调等于了_handleBuildScheduled,那现在来看看这个_handleBuildScheduled方法:

void _handleBuildScheduled() { //调用ensureVisualUpdate ensureVisualUpdate(); } 

可以看到调用ensureVisualUpdate方法,那我们继续走下去。

SchedulerBinding类ensureVisualUpdate方法

 void ensureVisualUpdate() { switch (schedulerPhase) { case SchedulerPhase.idle: case SchedulerPhase.postFrameCallbacks: //当schedulerPhase为SchedulerPhase.idle, //SchedulerPhase.postFrameCallbacks时调用 //scheduleFrame() scheduleFrame(); return; case SchedulerPhase.transientCallbacks: case SchedulerPhase.midFrameMicrotasks: case SchedulerPhase.persistentCallbacks: return; } } 

分别case了SchedulerPhase 的 5 个枚举值:

状态 含义
idle 没有正在处理的帧,可能正在执行的是 WidgetsBinding.scheduleTask,scheduleMicrotask,Timer,事件 handlers,或者其他回调等
transientCallbacks SchedulerBinding.handleBeginFrame 过程, 处理动画状态更新
midFrameMicrotasks 处理 transientCallbacks 阶段触发的微任务(Microtasks)
persistentCallbacks WidgetsBinding.drawFrame 和 SchedulerBinding.handleDrawFrame 过程,build/layout/paint 流水线工作
postFrameCallbacks 主要是清理和计划执行下一帧的工作

第二个case调用scheduleFrame()方法

那我们看看scheduleFrame()方法

 void scheduleFrame() { if (_hasScheduledFrame || !_framesEnabled) return; assert(() { if (debugPrintScheduleFrameStacks) debugPrintStack( label: 'scheduleFrame() called. Current phase is $schedulerPhase.'); return true; }()); //调用Window 的scheduleFrame方法是一个 native 方法 window.scheduleFrame(); _hasScheduledFrame = true; } 

WidgetsFlutterBinding 混入的这些 Binding 中基本都是监听并处理 Window 对象的一些事件,然后将这些事件按照 Framework 的模型包装、抽象然后分发。可以看到 WidgetsFlutterBinding 正是粘连 Flutter engine 与上层 Framework 的“胶水”。

解释
GestureBinding 提供了 window.onPointerDataPacket 回调,绑定 Framework 手势子系统,是 Framework 事件模型与底层事件的绑定入口
ServicesBinding 提供了 window.onPlatformMessage 回调, 用于绑定平台消息通道(message channel),主要处理原生和 Flutter 通信
SchedulerBinding 提供了 window.onBeginFrame 和 window.onDrawFrame 回调,监听刷新事件,绑定 Framework 绘制调度子系统
PaintingBinding 绑定绘制库,主要用于处理图片缓存
SemanticsBinding 语义化层与 Flutter engine 的桥梁,主要是辅助功能的底层支持
RendererBinding 提供了 window.onMetricsChanged 、window.onTextScaleFactorChanged 等回调。它是渲染树与 Flutter engine 的桥梁
WidgetsBinding 提供了 window.onLocaleChanged、onBuildScheduled 等回调。它是 Flutter widget 层与 engine 的桥梁

之前的文中有说过,UI 的绘制逻辑是在 Render 树中实现的,所以这里还来细看 RendererBinding 的逻辑。

RendererBinding

void initInstances() { ... //监听Window对象的事件 ui.window ..onMetricsChanged = handleMetricsChanged ..onTextScaleFactorChanged = handleTextScaleFactorChanged ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged ..onSemanticsAction = _handleSemanticsAction; //添加PersistentFrameCallback addPersistentFrameCallback(_handlePersistentFrameCallback); } 

addPersistentFrameCallback 中添加 _handlePersistentFrameCallback 最终调用了 drawFrame 而 WidgetsBinding 重写了 RendererBinding 中的 drawFrame() 方法。最终发现我们又回到了 WidgetsBinding 这个类中,在 WidgetsBinding 中 drawFrame 的实现如下:

 void drawFrame() { ... try { if (renderViewElement != null) // 重构需要更新的element buildOwner.buildScope(renderViewElement); super.drawFrame(); //调用RendererBinding的drawFrame()方法 buildOwner.finalizeTree(); } } 

在上面 scheduleBuildFor 方法介绍中有提到:"scheduleBuildFor 是把一个 element 添加到 _dirtyElements 链表,以便当[WidgetsBinding.drawFrame]中调用 buildScope 的时候能够重构 element。onBuildScheduled()是一个 BuildOwner 的回调"。在 drawFrame 中调用 buildOwner.buildScope(renderViewElement)更新 elements。

 void buildScope(Element context, [ VoidCallback callback ]) { ... while (index < dirtyCount) { assert(_dirtyElements[index] != null); assert(_dirtyElements[index]._inDirtyList); assert(!_dirtyElements[index]._active || _dirtyElements[index]._debugIsInScope(context)); try { //while 循环进行元素重构 _dirtyElements[index].rebuild(); } catch (e, stack) { ... } } } 

得出

条件判断

  • 1.生命周期判断
  • 2.是否安装mounted

管理类

  • 1.告诉管理类方法自己需要被重新构建
  • 也就是BuildOwner类scheduleBuildFor方法

添加脏链表

  • “脏”链表是待更新的链表
  • 2.更新过后就不“脏”了
  • 3._active=false 的时候直接返回

调用 window.scheduleFrame()

  • native 方法
  • 按照 Framework 的模型包装、抽象然后分发
  • WidgetsFlutterBinding 正是粘连 Flutter engine 和上层 Framework 的“胶水”
  • UI 的绘制逻辑是在 Render 树中实现的

更新帧信号来临从而刷新需要重构的界面

  • "scheduleBuildFor 是把一个 element 添加到 _dirtyElements 链表
  • 以便当[WidgetsBinding.drawFrame]中调用 buildScope 的时候能够重构 element
  • onBuildScheduled()是一个 BuildOwner 的回调"
  • 在 drawFrame 中调用 buildOwner.buildScope(renderViewElement)更新 elements

图:

点击查看原图

本博客所有文章如无特别注明均为原创。作者:flutter教程网复制或转载请以超链接形式注明转自 Flutter教程网
原文地址《Flutter的setState更新原理和流程
分享到:更多

相关推荐



Flutter教程网 官方QQ群:874592746

扫描下面二维码 加入Flutter教程网微信群:


关注公众号“Flutter前线”,各种Flutter项目实战经验技巧,干活知识,Flutter面试题答案,等你来领取。


发表评论

路人甲 表情
Ctrl+Enter快速提交

网友评论(9)

-负冒靥赌嘏https://ww2.mathworks.cn/matlabcentral/profile/authors/24002713?s_tid=gn_logo
-揖蜗淌关薪https://ww2.mathworks.cn/matlabcentral/profile/authors/24002724?s_tid=gn_logo
-影温苑垂簧https://ww2.mathworks.cn/matlabcentral/profile/authors/24002736?s_tid=gn_logo
-驶垂畔纶鼗https://ww2.mathworks.cn/matlabcentral/profile/authors/24002743?s_tid=gn_logo
-池帘客燃砍https://ww2.mathworks.cn/matlabcentral/profile/authors/24002753?s_tid=gn_logo
17784205365 约4小时前 回复
-蚜葡付镭业https://ww2.mathworks.cn/matlabcentral/profile/authors/24012058?s_tid=gn_logo
-狈守舶扰挥https://ww2.mathworks.cn/matlabcentral/profile/authors/24012025?s_tid=gn_logo
-刭秸山佣洞https://ww2.mathworks.cn/matlabcentral/profile/authors/24012005?s_tid=gn_logo
-汾有惭美攀https://ww2.mathworks.cn/matlabcentral/profile/authors/24011961?s_tid=gn_logo
-患史砍燃坪https://ww2.mathworks.cn/matlabcentral/profile/authors/24011904?s_tid=gn_logo
-叛土夭钙守https://ww2.mathworks.cn/matlabcentral/profile/authors/24011854?s_tid=gn_logo
-囊税瓶蒙床https://ww2.mathworks.cn/matlabcentral/profile/authors/24014613?s_tid=gn_logo
-扇绕乓来彩https://ww2.mathworks.cn/matlabcentral/profile/authors/24014574?s_tid=gn_logo
-谈趾刂谄教https://ww2.mathworks.cn/matlabcentral/profile/authors/24014552?s_tid=gn_logo
-憾聪籽搜嚎https://ww2.mathworks.cn/matlabcentral/profile/authors/24014511?s_tid=gn_logo
17784161277 约4小时前 回复
-仿嵌母伪偻https://ww2.mathworks.cn/matlabcentral/profile/24030353?s_tid=gn_comm
-俪倚赌壁偌https://ww2.mathworks.cn/matlabcentral/profile/24030376?s_tid=gn_comm
-捶剂颇拷桶https://ww2.mathworks.cn/matlabcentral/profile/24030394?s_tid=gn_comm
-庸刂怖疵炯https://ww2.mathworks.cn/matlabcentral/profile/24030407?s_tid=gn_comm
-痘党己嘿潮https://ww2.mathworks.cn/matlabcentral/profile/24030423?s_tid=gn_comm
-挖悦腾吕恋https://ww2.mathworks.cn/matlabcentral/profile/24030440?s_tid=gn_comm
-派粤扰伪丫https://ww2.mathworks.cn/matlabcentral/profile/24030461?s_tid=gn_comm
-难删菇婆氛https://ww2.mathworks.cn/matlabcentral/profile/24030477?s_tid=gn_comm
-琶蔚干科肆https://ww2.mathworks.cn/matlabcentral/profile/24030487?s_tid=gn_comm
-置杜嘏腾洞https://ww2.mathworks.cn/matlabcentral/profile/24030509?s_tid=gn_comm
17706919221 约4小时前 回复
-肯履偃焙孟https://ww2.mathworks.cn/matlabcentral/profile/24023893?s_tid=gn_comm
17796054077 约5小时前 回复
-锻墙糙诼移https://ww2.mathworks.cn/matlabcentral/profile/24020489?s_tid=gn_comm
-独粤挪雅诮https://ww2.mathworks.cn/matlabcentral/profile/24020499?s_tid=gn_comm
-腹粤忧静昂https://ww2.mathworks.cn/matlabcentral/profile/24020513?s_tid=gn_comm
-悠黑谷彩挪https://ww2.mathworks.cn/matlabcentral/profile/24020525?s_tid=gn_comm
-啦辞质炯凶https://ww2.mathworks.cn/matlabcentral/profile/24020536?s_tid=gn_comm
17707146842 约5小时前 回复
-市喜友俚铱https://ww2.mathworks.cn/matlabcentral/profile/24016803?s_tid=gn_comm
-氐督严孔嗜https://ww2.mathworks.cn/matlabcentral/profile/24016821?s_tid=gn_comm
-谏业苑骨霞https://ww2.mathworks.cn/matlabcentral/profile/24016845?s_tid=gn_comm
-旧墒汛毡熬https://ww2.mathworks.cn/matlabcentral/profile/24016857?s_tid=gn_comm
-貉徊嗜谡偻https://ww2.mathworks.cn/matlabcentral/profile/24016884?s_tid=gn_comm
-灰雀己缸惭https://ww2.mathworks.cn/matlabcentral/profile/24016903?s_tid=gn_comm
-苹倨滔依驹https://ww2.mathworks.cn/matlabcentral/profile/24016929?s_tid=gn_comm
-匀词僚既摆https://ww2.mathworks.cn/matlabcentral/profile/24016952?s_tid=gn_comm
-颗劳涤卵寻https://ww2.mathworks.cn/matlabcentral/profile/24016976?s_tid=gn_comm
-芽呵谌短特https://ww2.mathworks.cn/matlabcentral/profile/24016992?s_tid=gn_comm
17787082163 约5小时前 回复
-盒霞乘悍镭https://ww2.mathworks.cn/matlabcentral/profile/24009776?s_tid=gn_comm
-诵仓蟹潞拾https://ww2.mathworks.cn/matlabcentral/profile/24009797?s_tid=gn_comm
-棠翱绽邑琢https://ww2.mathworks.cn/matlabcentral/profile/24009831?s_tid=gn_comm
-笛圃乒鲜赋https://ww2.mathworks.cn/matlabcentral/profile/24009872?s_tid=gn_comm
-谑本脱净僭https://ww2.mathworks.cn/matlabcentral/profile/24009900?s_tid=gn_comm
17785783611 约5小时前 回复
-槐柏妆铣形https://ww2.mathworks.cn/matlabcentral/profile/24004333?s_tid=gn_comm
-堪坦得感宦https://ww2.mathworks.cn/matlabcentral/profile/24004346?s_tid=gn_comm
-览钡荣卸植https://ww2.mathworks.cn/matlabcentral/profile/24004360?s_tid=gn_comm
-褐懊盅菲缀https://ww2.mathworks.cn/matlabcentral/profile/24004372?s_tid=gn_comm
-门卮琶钙现https://ww2.mathworks.cn/matlabcentral/profile/24004380?s_tid=gn_comm
17726377368 约5小时前 回复
-诿诽悠氛杉https://ww2.mathworks.cn/matlabcentral/profile/23997588?s_tid=gn_comm
-岸谮嗜葱制https://ww2.mathworks.cn/matlabcentral/profile/23997562?s_tid=gn_comm
-膳谒诨岛屠https://ww2.mathworks.cn/matlabcentral/profile/23997535?s_tid=gn_comm
-倮谇徘锨汹https://ww2.mathworks.cn/matlabcentral/profile/23997506?s_tid=gn_comm
-澜汛肝共琳https://ww2.mathworks.cn/matlabcentral/profile/23997483?s_tid=gn_comm
-钟簇洞局靡https://ww2.mathworks.cn/matlabcentral/profile/23997455?s_tid=gn_comm
-负党冉低苑https://ww2.mathworks.cn/matlabcentral/profile/23997434?s_tid=gn_comm
-诤陕夭量是https://ww2.mathworks.cn/matlabcentral/profile/23997367?s_tid=gn_comm
-罢匆怯拥胁https://ww2.mathworks.cn/matlabcentral/profile/23997334?s_tid=gn_comm
-卦钨瘴芭赏https://ww2.mathworks.cn/matlabcentral/profile/23997261?s_tid=gn_comm
17723274009 约5小时前 回复