Flutter笔记-深入分析Widget 1

ps: 文中flutter源码版本 1.0.0

《Flutter笔记-深入分析Widget 1》 widget关系树

widget基本分为StatelessWidget、StatefulWidget、RenderObjectWidget和ProxyWidget 4类型(子类PreferredSizeWidget是一个接口)
先从最简单的开始分析:

StatelessWidget

1. 这是什么?

StatelessWidget是一个无状态的控件,之前我们只关心其的build方法,那么其的build是什么时候调用的呢?

abstract class StatelessWidget extends Widget {

  const StatelessWidget({ Key key }) : super(key: key);

  @override
  StatelessElement createElement() => StatelessElement(this);

  @protected
  Widget build(BuildContext context);
}

class StatelessElement extends ComponentElement {
  StatelessElement(StatelessWidget widget) : super(widget);
  //这种写法在flutter中比较常见
  //widget就是StatelessWidget的createElement()方法中传递的this
  @override
  StatelessWidget get widget => super.widget;

  //调用StatelessWidget中的build
  @override
  Widget build() => widget.build(this);

  @override
  void update(StatelessWidget newWidget) {
    super.update(newWidget);
    assert(widget == newWidget);
    _dirty = true;
    rebuild();
  }
}

这个问题就转换为什么时候调用StatelessElement中的build方法
带着这个问题,我们从头开始捋

2. 定义一个起点

flutter的main函数初始都是这么写的,ok,我们就按这个顺序分析下来

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp();
  }
}

后续过程中很多源码其实之前已经分析过,这里还是过一下。先看runApp方法:

void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized()
    ..attachRootWidget(app)
    ..scheduleWarmUpFrame();
}

我们只关心直接的MyAPP控件是什么时候build的,所以直接看attachRootWidget(app)

void attachRootWidget(Widget rootWidget) {
  _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
    container: renderView,
    debugShortDescription: '[root]',
    child: rootWidget
  ).attachToRenderTree(buildOwner, renderViewElement);
}

创建了一个RenderObjectToWidgetAdapter控件,并调用了attachToRenderTree方法

class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
  RenderObjectToWidgetAdapter({
    this.child,
    this.container,
    this.debugShortDescription
  }) : super(key: GlobalObjectKey(container));

  final String debugShortDescription;

  @override
  RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);

  @override
  RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container;

  @override
  void updateRenderObject(BuildContext context, RenderObject renderObject) { }

  RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [RenderObjectToWidgetElement<T> element]) {
    //不存在则创建一个
    if (element == null) {
      owner.lockState(() {
        //创建了一个RenderObjectToWidgetElement
        element = createElement();
        assert(element != null);
        element.assignOwner(owner);
      });
      owner.buildScope(element, () {
        //进行登记
        element.mount(null, null);
      });
    } else {
      element._newWidget = this;
      element.markNeedsBuild();
    }
    return element;
  }

来到RenderObjectToWidgetElement中的mount方法

@override
void mount(Element parent, dynamic newSlot) {
  assert(parent == null);
  super.mount(parent, newSlot);
  _rebuild();
}

void _rebuild() {
  try {
    //这里传递的是widget.child,widget就是RenderObjectToWidgetAdapter
    //child即是MyApp控件
    //参数_child为未更新前的child,初始为null
    _child = updateChild(_child, widget.child, _rootChildSlot);
    assert(_child != null);
  } catch (exception, stack) {
    ...
    );
    ...
  }
}

updateChild在基础父类Element中

@protected
Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
  ...
  //本次的child是未null的,只要再次调用rebuild才有值
  if (newWidget == null) {
    if (child != null)
      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)) {
      if (child.slot != newSlot)
        updateSlotForChild(child, newSlot);
      //执行这一步的条件必须是child有值,但第一次调用build方法时,child为null,只有第二次后才有值
      //这里会调用Element中的update方法
      child.update(newWidget);
      ...
      return child;
    }
    deactivateChild(child);
    assert(child._parent == null);
  }
  return inflateWidget(newWidget, newSlot);
}
//类型和key相同则表示同一个控件
static bool canUpdate(Widget oldWidget, Widget newWidget) {
  return oldWidget.runtimeType == newWidget.runtimeType
      && oldWidget.key == newWidget.key; 
}

渲染控件,并且向下遍历

@protected
Element inflateWidget(Widget newWidget, dynamic newSlot) {
  //省略断言判断  
  ...
  //newWidget即是MyApp,是一个StatelessWidget,所以创建了一个StatelessElement
  final Element newChild = newWidget.createElement();
  assert(() { _debugCheckForCycles(newChild); return true; }());
  //StatelessElement中的mount
  newChild.mount(this, newSlot);
  assert(newChild._debugLifecycleState == _ElementLifecycle.active);
  return newChild;
}

StatelessElement中无mount方法,在其父类ComponentElement找到

@override
void mount(Element parent, dynamic newSlot) {
  super.mount(parent, newSlot);
  assert(_child == null);
  assert(_active);
  _firstBuild();
  assert(_child != null);
}
  
void _firstBuild() {
  rebuild();
}

ComponentElement无rebuild,寻找其父类Element中方法

void rebuild() {
   //省略断言判断
  ...
  performRebuild();
  ...
}

再回到ComponentElement,找到其performRebuild(),此时就很明朗了

@override
void performRebuild() {
  //省略了断言和错误处理
  ...    
  Widget built;
  try {
    //调用StatelessElement中的build()方法
    built = build();
    debugWidgetBuilderValue(widget, built);
  } catch (e, stack) {
    ...
  } finally {
    ...
  }
  try {
     //遍历下去
      _child = updateChild(_child, built, slot);
      assert(_child != null);
  } catch (e, stack) {
     ...
  }
  ...
}

至此,build的流程就结束了

StatefulWidget

1. 这是什么?

StatefulWidget是一个有状态的控件,build调用的流程和上面是一样的,先StatefulElement的build方法,然后调用state中的build方法

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);

  @override
  StatefulElement createElement() => StatefulElement(this);

  @protected
  State createState();
}

2. state生命周期

《Flutter笔记-深入分析Widget 1》 state生命周期

其实也就是widget的element的创建、改变和消除的生命周期
我们按照这个图过一下state的生命周期的源码执行顺序:

class StatefulElement extends ComponentElement {
  StatefulElement(StatefulWidget widget)
    // --- 1. 构造函数创建state
    : _state = widget.createState(), super(widget) {
   //省略了断言判断
   ...
    _state._element = this;
    _state._widget = widget;
   
  }

  // --- 4. 调用build()方法,显示在树上
  @override
  Widget build() => state.build(this);

  State<StatefulWidget> get state => _state;
  State<StatefulWidget> _state;

  @override
  void _reassemble() {
    state.reassemble();
    super._reassemble();
  }

  @override
  void _firstBuild() {
    ...
    try {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      // --- 2. 调用initState()
      final dynamic debugCheckForReturnedFuture = _state.initState() as dynamic;
      ...
    } finally {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
    }
    ...
     // --- 3. 调用didChangeDependencies()
    _state.didChangeDependencies();
    ...
    super._firstBuild();
  }

  // --- 5. 控件第二次调用自己的build方法时调用,即外部使用setState,重新绘制子树
  @override
  void update(StatefulWidget newWidget) {
    super.update(newWidget);
    final StatefulWidget oldWidget = _state._widget;
    _dirty = true;
    _state._widget = widget;
    try {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      // --- 6. 调用didUpdateWidget()
      final dynamic debugCheckForReturnedFuture = _state.didUpdateWidget(oldWidget) as dynamic;
      ...
    } finally {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
    }
    // --- 7. 执行build
    rebuild();
  }
  //build组件时调用,代表组件是活跃状态
  @override
  void activate() {
    super.activate();
    assert(_active); 
    markNeedsBuild();
  }
  //build控件时调用,代表组件是非活跃状态
  @override
  void deactivate() {
    _state.deactivate();
    super.deactivate();
  }
  //drawFrame时清空空闲控件时,若空闲则调用,解除登记
  @override
  void unmount() {
    super.unmount();
    _state.dispose();
    ...
    _state._element = null;
    _state = null;
  }

  @override
  InheritedWidget inheritFromElement(Element ancestor, { Object aspect }) {
    ...
    return super.inheritFromElement(ancestor, aspect: aspect);
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _state.didChangeDependencies();
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<State<StatefulWidget>>('state', state, defaultValue: null));
  }
}

3. setState 更新状态

state进行更新,执行setState方法,这个之前分析过,这里贴个图:

《Flutter笔记-深入分析Widget 1》 setState流程.png

@protected
void setState(VoidCallback fn) {
  //去除断言
  ...
  final dynamic result = fn() as dynamic;
  _element.markNeedsBuild();
}

void markNeedsBuild() {
  ...
  if (dirty)
    return;
  _dirty = true;
  owner.scheduleBuildFor(this);
}

//对修改的脏数据进行标记和添加到列表中
void scheduleBuildFor(Element element) {
  ...
  if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
    _scheduledFlushDirtyElements = true;
    onBuildScheduled();
  }
  //添加_dirtyElements列表中
  _dirtyElements.add(element);
  //标记
  element._inDirtyList = true;
  ...
}

最后会通过c/c++回调drawFrame方法

 @override
  void drawFrame() {
    ...
    try {
      if (renderViewElement != null)
        //执行rebuild,再次调用StatefulWidget的build方法
        buildOwner.buildScope(renderViewElement);
      //绘制
      super.drawFrame();
      //释放空闲,解除登记
      buildOwner.finalizeTree();
    } finally {
      ...
    }
    ...
  }

执行rebuild方法

void buildScope(Element context, [VoidCallback callback]) {
    if (callback == null && _dirtyElements.isEmpty)
      return;
    ...
    Timeline.startSync('Build', arguments: timelineWhitelistArguments);
    try {
      _scheduledFlushDirtyElements = true;
      if (callback != null) {
        assert(_debugStateLocked);
        Element debugPreviousBuildTarget;
        ...
        _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) {
          ...
        }
        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 (Element element in _dirtyElements) {
        assert(element._inDirtyList);
        element._inDirtyList = false;
      }
      _dirtyElements.clear();
      _scheduledFlushDirtyElements = false;
      _dirtyElementsNeedsResorting = null;
      Timeline.finishSync();
      ...
    }
    ...
  }

RenderObjectWidget

1.这是什么?

abstract class RenderObjectWidget extends Widget {
  const RenderObjectWidget({ Key key }) : super(key: key);

  @override
  RenderObjectElement createElement();

  @protected
  RenderObject createRenderObject(BuildContext context);

  @protected
  void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }

  @protected
  void didUnmountRenderObject(covariant RenderObject renderObject) { }
}

除了继承来的createElement()方法,还新增了3个方法,这次主要研究这三个方法调用的时机

RenderObjectWidget是一个抽象类,createElement()并未像之前一样实现了,但是没关系,我们可以看到其的返回类型是RenderObjectElement,这是返回通用的父类

abstract class RenderObjectElement extends Element {
  RenderObjectElement(RenderObjectWidget widget) : super(widget);

  @override
  RenderObjectWidget get widget => super.widget;

  @override
  RenderObject get renderObject => _renderObject;
  RenderObject _renderObject;

  ...

  @override
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    // -- 1.
    _renderObject = widget.createRenderObject(this);
    assert(() { _debugUpdateRenderObjectOwner(); return true; }());
    assert(_slot == newSlot);
    attachRenderObject(newSlot);
    _dirty = false;
  }

  @override
  void update(covariant RenderObjectWidget newWidget) {
    super.update(newWidget);
    assert(widget == newWidget);
    assert(() { _debugUpdateRenderObjectOwner(); return true; }());
    // -- 2.
    widget.updateRenderObject(this, renderObject);
    _dirty = false;
  }

  @override
  void performRebuild() {
    // -- 2.
    widget.updateRenderObject(this, renderObject);
    _dirty = false;
  }

  ...
 
  @override
  void unmount() {
    super.unmount();
    //省略断言
    ...
    // -- 3.
    widget.didUnmountRenderObject(renderObject);
  }

  ...
}

经过前面的分析 ,其实本身比较简单,复杂的部分都在RenderObject上,如何摆放和绘制

针对ProxyWidget放在下一篇:深入分析Widget 2

    原文作者:叶落清秋
    原文地址: https://www.jianshu.com/p/e48d8332616d
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞