众所周知,Flutter中的UI都是通过Widget来呈现给用户看的。Android中的UI我们都很了解,主要是通过View和ViewGroup来呈现给用户看的。Android view或ViewGroup的属性,子View的添加删除,生命周期管理,测量,布局,绘制等操作都是由View或ViewGroup本身来管理的。然而Flutter中属性,配置等信息是由Widget来管理的。Widget的增加,删除操作是由Element类来管理的。测量,布局,绘制等操作是由RenderObject对象来管理的。本文让我来探究Flutter界面更新操作的原理。
从main()方法说起
void main() => runApp(MyApp()); //mixin WidgetsBinding void runApp(Widget app) { WidgetsFlutterBinding.ensureInitialized() ..scheduleAttachRootWidget(app) ..scheduleWarmUpFrame(); } //WidgetsBinding @protected void scheduleAttachRootWidget(Widget rootWidget) { Timer.run(() { attachRootWidget(rootWidget); }); } //WidgetsBinding void attachRootWidget(Widget rootWidget) { _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>( container: renderView, debugShortDescription: '[root]', child: rootWidget, ).attachToRenderTree(buildOwner, renderViewElement); }
在attachRootWidget(Widget rootWidget)方法中。我们创建了RenderObjectToWidgetAdapter对象,并且把MyApp对象赋值给它的child对象。我们来看下RenderObjectToWidgetAdapter。首先我们看到下RenderObjectToWidgetAdapter是个Widget的子类。它是整个Flutter项目的根Widget,对标Android的DecorView。
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget { RenderObjectToWidgetAdapter({ this.child, this.container, this.debugShortDescription, }) : super(key: GlobalObjectKey(container)); /// The widget below this widget in the tree. /// /// {@macro flutter.widgets.child} final Widget child; /// The [RenderObject] that is the parent of the [Element] created by this widget. final RenderObjectWithChildMixin<T> container; /// A short description of this widget used by debugging aids. final String debugShortDescription; @override RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this); @override RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container; @override void updateRenderObject(BuildContext context, RenderObject renderObject) { } /// Inflate this widget and actually set the resulting [RenderObject] as the /// child of [container]. /// /// If `element` is null, this function will create a new element. Otherwise, /// the given element will have an update scheduled to switch to this widget. /// /// Used by [runApp] to bootstrap applications. RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T> element ]) { if (element == null) { owner.lockState(() { element = createElement();//创建RenderObjectToWidgetElement() assert(element != null); element.assignOwner(owner); }); owner.buildScope(element, () { element.mount(null, null);//_rebuild自己,rebuild dirty Elements }); // This is most likely the first time the framework is ready to produce // a frame. Ensure that we are asked for one. SchedulerBinding.instance.ensureVisualUpdate(); } else { element._newWidget = this; element.markNeedsBuild(); } return element; } @override String toStringShort() => debugShortDescription ?? super.toStringShort(); }
创建完调用RenderObjectToWidgetAdapter之后,调用它的attachToRenderTree方法。该方法的主要功能是
如果Element为空,创建新的Element
将Element与Widget关联起来
调用element的mount方法,将Element加入到renderTree中
RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T> element ]) { if (element == null) { owner.lockState(() { element = createElement();//创建RenderObjectToWidgetElement() assert(element != null); element.assignOwner(owner); }); owner.buildScope(element, () { element.mount(null, null);//_rebuild自己,rebuild dirty Elements }); // This is most likely the first time the framework is ready to produce // a frame. Ensure that we are asked for one. SchedulerBinding.instance.ensureVisualUpdate(); } else { element._newWidget = this; element.markNeedsBuild(); } return element; }
owner.buildScope(),首先调用的是callback(),也就是element.mount(null,null)。然后会遍历脏的Element并调用rebuild()方法
// BuildOwner void buildScope(Element context, [ VoidCallback callback ]) { if (callback == null && _dirtyElements.isEmpty) return; try { _scheduledFlushDirtyElements = true; if (callback != null) { _dirtyElementsNeedsResorting = false; try { callback(); } finally { } } _dirtyElements.sort(Element._sort); _dirtyElementsNeedsResorting = false; int dirtyCount = _dirtyElements.length; int index = 0; while (index < dirtyCount) { try { _dirtyElements[index].rebuild(); } catch (e, stack) { _debugReportException( ErrorDescription('while rebuilding dirty elements'), e, stack, informationCollector: () sync* { yield DiagnosticsDebugCreator(DebugCreator(_dirtyElements[index])); yield _dirtyElements[index].describeElement('The element being rebuilt at the time was index $index of $dirtyCount'); }, ); } index += 1; if (dirtyCount < _dirtyElements.length || _dirtyElementsNeedsResorting) { _dirtyElements.sort(Element._sort); _dirtyElementsNeedsResorting = false; dirtyCount = _dirtyElements.length; while (index > 0 && _dirtyElements[index - 1].dirty) { // It is possible for previously dirty but inactive widgets to move right in the list. // We therefore have to move the index left in the list to account for this. // We don't know how many could have moved. However, we do know that the only possible // change to the list is that nodes that were previously to the left of the index have // now moved to be to the right of the right-most cleaned node, and we do know that // all the clean nodes were to the left of the index. So we move the index left // until just after the right-most clean node. index -= 1; } } } } finally { for (Element element in _dirtyElements) { assert(element._inDirtyList); element._inDirtyList = false; } _dirtyElements.clear(); _scheduledFlushDirtyElements = false; _dirtyElementsNeedsResorting = null; Timeline.finishSync(); assert(_debugBuilding); assert(() { _debugBuilding = false; _debugStateLockLevel -= 1; if (debugPrintBuildScope) debugPrint('buildScope finished'); return true; }()); } assert(_debugStateLockLevel >= 0); }
element.mount(Element parent, dynamic newSlot)
//RenderObjectToWidgetElement @override void mount(Element parent, dynamic newSlot) { assert(parent == null); super.mount(parent, newSlot); _rebuild(); }
该方法主要完成两个功能
- 通过super.mount(parent,newSlot)将,当前的Element添加到Element Tree中
- 通过_rebuild()把子Widget渲染出来
我们来分析下mount方法,看他是如何将当前的Element添加到Element Tree中的 //RenderObjectToWidgetElement @override void mount(Element parent, dynamic newSlot) { assert(parent == null); super.mount(parent, newSlot); _rebuild(); } // RootRenderObjectElement @override void mount(Element parent, dynamic newSlot) { // Root elements should never have parents. assert(parent == null); assert(newSlot == null); super.mount(parent, newSlot); } //RenderObjectElement //完成Element添加到Element Tree后 会将RenderObject添加到RenderObject Tree中 @override void mount(Element parent, dynamic newSlot) { super.mount(parent, newSlot); _renderObject = widget.createRenderObject(this); assert(() { _debugUpdateRenderObjectOwner(); return true; }()); assert(_slot == newSlot); attachRenderObject(newSlot); _dirty = false; } //Element @mustCallSuper void mount(Element parent, dynamic newSlot) { assert(_debugLifecycleState == _ElementLifecycle.initial); assert(widget != null); assert(_parent == null); assert(parent == null || parent._debugLifecycleState == _ElementLifecycle.active); assert(slot == null); assert(depth == null); assert(!_active); _parent = parent; _slot = newSlot; _depth = _parent != null ? _parent.depth + 1 : 1; _active = true; if (parent != null) // Only assign ownership if the parent is non-null _owner = parent.owner; if (widget.key is GlobalKey) { final GlobalKey key = widget.key; key._register(this); } _updateInheritance(); assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; }()); }
总之mount的功能就是将Element和RenderObject加入到各自的渲染树中
接下来分析RenderObjectToWidgetElement._rebuild(),该方法的作用就是渲染出Element的子Widget
void _rebuild() { try { _child = updateChild(_child, widget.child, _rootChildSlot); assert(_child != null); } catch (exception, stack) { final FlutterErrorDetails details = FlutterErrorDetails( exception: exception, stack: stack, library: 'widgets library', context: ErrorDescription('attaching to the render tree'), ); FlutterError.reportError(details); final Widget error = ErrorWidget.builder(details); _child = updateChild(null, error, _rootChildSlot); } } @protected Element updateChild(Element child, Widget newWidget, dynamic newSlot) { assert(() { if (newWidget != null && newWidget.key is GlobalKey) { final GlobalKey key = newWidget.key; key._debugReserveFor(this); } return true; }()); if (newWidget == null) { if (child != null) //如果newWiget为null 而且child(Element)不为null,将child 和其对应的RenderObject从其对应的Tree中移除 deactivateChild(child); return null; } if (child != null) { if (child.widget == newWidget) { if (child.slot != newSlot) updateSlotForChild(child, newSlot); return child; } if (Widget.canUpdate(child.widget, newWidget)) { //如果新老Widget的类型相同,而且key相同,直接update if (child.slot != newSlot) updateSlotForChild(child, newSlot); child.update(newWidget); assert(child.widget == newWidget); assert(() { child.owner._debugElementWasRebuilt(child); return true; }()); return child; } //将子Element从树中移除, deactivateChild(child); assert(child._parent == null); } return inflateWidget(newWidget, newSlot); } //1.优先通过GlobalKey复用Element //2.创建新的Element @protected Element inflateWidget(Widget newWidget, dynamic newSlot) { assert(newWidget != null); final Key key = newWidget.key; if (key is GlobalKey) {// final Element newChild = _retakeInactiveElement(key, newWidget); if (newChild != null) { assert(newChild._parent == null); assert(() { _debugCheckForCycles(newChild); return true; }()); newChild._activateWithParent(this, newSlot); final Element updatedChild = updateChild(newChild, newWidget, newSlot); assert(newChild == updatedChild); return updatedChild; } } final Element newChild = newWidget.createElement(); assert(() { _debugCheckForCycles(newChild); return true; }()); newChild.mount(this, newSlot);//将子Element插入到父Element树中 assert(newChild._debugLifecycleState == _ElementLifecycle.active); return newChild; }