博主相关文章列表
Flutter 框架实现原理
Flutter 框架层启动源码剖析
Flutter 页面更新流程剖析
Flutter 事件处理源码剖析
Flutter 路由源码剖析
Flutter 安卓平台源码剖析(一)
Flutter 自定义控件之RenderObject
当我们需要更新页面时,会调用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方法。官方对该方法做了解释
请求在下一个适当的机会调用
onBeginFrame
和onDrawFrame
回调
void scheduleFrame() native 'Window_scheduleFrame';
这里就不跟踪C++中的具体实现了,依照给出的解释,我们查看onBeginFrame
和onDrawFrame
回调
/// [SchedulerBinding]
void _handleBeginFrame(Duration rawTimeStamp) {
if (_warmUpFrame) {
_ignoreNextEngineDrawFrame = true;
return;
}
handleBeginFrame(rawTimeStamp);
}
void _handleDrawFrame() {
if (_ignoreNextEngineDrawFrame) {
_ignoreNextEngineDrawFrame = false;
return;
}
handleDrawFrame();
}
到这里,正好对应上了我们在《框架启动源码剖析》渲染部分剖析的逻辑,关于handleDrawFrame
的后续调用,请 跳转前文,这里直接查看我们关注的逻辑,主要在buildOwner
的buildScope
方法中
/// [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);
@override
StatelessWidget get widget => super.widget as StatelessWidget;
// build中的context参数实际上就是Widget对应的Element对象
@override
Widget build() => widget.build(this);
@override
void 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;
}
@override
Widget build() => _state.build(this);
State get state => _state;
State _state;
// ......省略......
}
当需要更新页面的时候,由应用上层通知到Engine,Engine会等到下个Vsync信号到达的时候,去通知Framework上层,然后Framework会进行Animation
, Build
,Layout
,Compositing
,Paint
,最后生成layer
提交给Engine。Engine会把layer进行组合,生成纹理,最后通过OpenGl
接口提交数据给GPU, GPU经过处理后在显示器上面显示
如需要获取完整的Flutter全栈式开发课程,请访问以下地址
Flutter全栈式开发之Dart 编程指南
Flutter 全栈式开发指南