Flutter Provider原理深入浅出(中)

上文,我们大致分析了ChangeNotifierProviderConsumer的源码,但由于很多回调都是系统触发的,导致整个渲染的原理我们还没有盘清楚,带着之前遗留的问题,我们通过调试代码,来试图解开这些秘密。

1 我们在使用ChangeNotifierProvider的时候,最终是包装成_Delegate的子类_CreateInheritedProvider,然而createElement是谁调的
2 分析Consumer,最终在调用builder的时候使用到了系统回调contextcontext的类型为什么是SingleChildStatelessElement
3 在给builder传递参数的时候,使用的Provider.of(context)最终是使用Element类的_inheritedWidgets存储的InheritedElement,最终应用层拿到的T实际是inheritedElement.value,那InheritedElementT又是如何建立关系的

第一个问题:createElement,通过断点代码

_InheritedProviderScope.createElement (inherited_provider.dart:310)
Element.inflateWidget (framework.dart:3564)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
SingleChildWidgetElementMixin.mount (nested.dart:223)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
_NestedHookElement.mount (nested.dart:188)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
_InheritedProviderScopeElement.performRebuild (inherited_provider.dart:426)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
SingleChildWidgetElementMixin.mount (nested.dart:223)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
_NestedHookElement.mount (nested.dart:188)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
--------------------------------------------------------------------------------------------------
SingleChildWidgetElementMixin.mount (nested.dart:223)
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
RenderObjectToWidgetElement._rebuild (binding.dart:1252)
RenderObjectToWidgetElement.mount (binding.dart:1223)
--------------------------------------------------------------------------------------------------
RenderObjectToWidgetAdapter.attachToRenderTree. (binding.dart:1165)
BuildOwner.buildScope (framework.dart:2683)
--------------------------------------------------------------------------------------------------
RenderObjectToWidgetAdapter.attachToRenderTree (binding.dart:1164)
WidgetsBinding.attachRootWidget (binding.dart:974)
WidgetsBinding.scheduleAttachRootWidget. (binding.dart:955)
_rootRun (zone.dart:1182)
_CustomZone.run (zone.dart:1093)
_CustomZone.runGuarded (zone.dart:997)
_CustomZone.bindCallbackGuarded. (zone.dart:1037)
_rootRun (zone.dart:1190)
_CustomZone.run (zone.dart:1093)
_CustomZone.bindCallback. (zone.dart:1021)
Timer._createTimer. (timer_patch.dart:18)
_Timer._runTimers (timer_impl.dart:397)
_Timer._handleMessage (timer_impl.dart:428)
_RawReceivePortImpl._handleMessage (isolate_patch.dart:168)

我们看到,堆栈非常长,我们先从上往下看,inflateWidget主要作用应该是将布局文件实例化为View,ComponentElement调用mount时,最终调用到了ElementinflateWidget

从下往上看,是应用启动的流程

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

widgets/binding.dart
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {

  static WidgetsBinding ensureInitialized() {
    if (WidgetsBinding.instance == null)
      WidgetsFlutterBinding(); 
    return WidgetsBinding.instance;
  }
}

我们写一个app,入口都会是main函数,在Flutter App中main函数会调用runApp()方法,这里首先会调用ensureInitialized来初始化WidgetsBinding单例对象,WidgetsFlutterBinding继承BindingBase抽象类,并且附带7个mixin,会先调用父类的构造函数

  BindingBase() {
    developer.Timeline.startSync('Framework initialization');

    assert(!_debugInitialized);
    initInstances();
    assert(_debugInitialized);

    assert(!_debugServiceExtensionsRegistered);
    initServiceExtensions();
    assert(_debugServiceExtensionsRegistered);

    developer.postEvent('Flutter.FrameworkInitialization', {});

    developer.Timeline.finishSync();
  }

BindingBase构造的时候调用initInstancesinitServiceExtensions完成以下的工作:

  • 执行initInstances()方法会依次调用到每一个mixin来初始化一些状态;
  • 执行initServiceExtensions方法会依次调用WidgetsBinding,RendererBinding,SchedulerBinding,ServicesBinding,BindingBase这5个类,主要是根据不同的包(release/profile/debug)调用registerServiceExtension()方法来注册各种扩展服务用于debug。
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
  @override
  void initInstances() {
    super.initInstances();
    _instance = this;

    assert(() {
      _debugAddStackFilters();
      return true;
    }());

    // Initialization of [_buildOwner] has to be done after
    // [super.initInstances] is called, as it requires [ServicesBinding] to
    // properly setup the [defaultBinaryMessenger] instance.
    _buildOwner = BuildOwner();
    buildOwner.onBuildScheduled = _handleBuildScheduled;
    window.onLocaleChanged = handleLocaleChanged;
    window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
    SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
    FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator);
  }

WidgetsBinding初始化过程会设置window的如下回调方法:

  • onLocaleChanged
  • onAccessibilityFeaturesChanged

其它几种Binding暂时不展开说,继续围绕WidgetsBinding来深入分析,ensureInitialized拿到了WidgetsBinding的单例对象,调用attachRootWidget

void scheduleAttachRootWidget(Widget rootWidget) {
    Timer.run(() {
      attachRootWidget(rootWidget);
    });
  }

scheduleAttachRootWidget添加异步任务attachRootWidgetTimer.run官方给的解释是尽快执行一个异步任务,其实就是把attachRootWidget这个任务异步来执行,不影响当前程序继续执行

 /**
   * Runs the given [callback] asynchronously as soon as possible.
   *
   * This function is equivalent to `new Timer(Duration.zero, callback)`.
   */
  static void run(void Function() callback) {
    new Timer(Duration.zero, callback);
  }
/// Takes a widget and attaches it to the [renderViewElement], creating it if
  /// necessary.
  ///
  /// This is called by [runApp] to configure the widget tree.
  ///
  /// See also:
  ///
  ///  * [RenderObjectToWidgetAdapter.attachToRenderTree], which inflates a
  ///    widget and attaches it to the render tree.
  void attachRootWidget(Widget rootWidget) {
    _readyToProduceFrames = true;
    _renderViewElement = RenderObjectToWidgetAdapter(
      container: renderView,
      debugShortDescription: '[root]',
      child: rootWidget,
    ).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement);
  }

来到了attachRootWidget的实现,通过RenderObjectToWidgetAdapter将传入的Widget转成Element,至此我们知道,WidgetElement建立了关系,我们再详细分析下renderViewRenderObjectToWidgetAdapter这个类

rendering/binding.dart

mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
  @override
  void initInstances() {
    super.initInstances();
    _instance = this;
    _pipelineOwner = PipelineOwner(
      onNeedVisualUpdate: ensureVisualUpdate,
      onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
      onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
    );
    window
      ..onMetricsChanged = handleMetricsChanged
      ..onTextScaleFactorChanged = handleTextScaleFactorChanged
      ..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
      ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
      ..onSemanticsAction = _handleSemanticsAction;
    initRenderView();
    _handleSemanticsEnabledChanged();
    assert(renderView != null);
    addPersistentFrameCallback(_handlePersistentFrameCallback);
    initMouseTracker();
  }

  void initRenderView() {
    assert(!_debugIsRenderViewInitialized);
    assert(() {
      _debugIsRenderViewInitialized = true;
      return true;
    }());
    renderView = RenderView(configuration: createViewConfiguration(), window: window);
    renderView.prepareInitialFrame();
  }

renderView是在RendererBinding初始化时候创建的,并将renderView存储在_pipelineOwner.rootNode,代码如下:

set renderView(RenderView value) {
    assert(value != null);
    _pipelineOwner.rootNode = value;
  }

再来看RenderObjectToWidgetAdapter类,这个类非常重要,它建立起了WidgetElement的关联

class RenderObjectToWidgetAdapter extends RenderObjectWidget {
  /// Creates a bridge from a [RenderObject] to an [Element] tree.
  ///
  /// Used by [WidgetsBinding] to attach the root widget to the [RenderView].
  RenderObjectToWidgetAdapter({
    this.child,
    this.container,
    this.debugShortDescription,
  }) : super(key: GlobalObjectKey(container));

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

  RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement element ]) {
    if (element == null) {
      owner.lockState(() {
        element = createElement();
        assert(element != null);
        element.assignOwner(owner);
      });
      owner.buildScope(element, () {
        element.mount(null, null);
      });
      // 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;
  }

RenderObjectWidget的子类,构造函数有三个参数childcontainerdebugShortDescriptionattachToRenderTree里如果element没有创建,就创建并返回它,如果创建了,就会使用已经创建的element。,在创建element的时候createElement调用了,我们本文开始设置的问题1终于有了答案,createElementRenderObjectToWidgetAdapter调用的,发生在创建element的时候,而调用createElement的时候,将this也就是RenderObjectToWidgetAdapter对象作为参数层层传递,最终给了Element,而this本身存储了Widget,存在了Elementwidget成员变量中

abstract class Element extends DiagnosticableTree implements BuildContext {
  /// Creates an element that uses the given widget as its configuration.
  ///
  /// Typically called by an override of [Widget.createElement].
  Element(Widget widget)
    : assert(widget != null),
      _widget = widget;

  Element _parent;

最终传递给抽象类Element构造函数中的widget也是RenderObjectToWidgetAdapter类的对象,element第一次创建后会调用element.mount(null, null); 并出现这些堆栈

SingleChildWidgetElementMixin.mount (nested.dart:223)
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
RenderObjectToWidgetElement._rebuild (binding.dart:1252)
RenderObjectToWidgetElement.mount (binding.dart:1223)
--------------------------------------------------------------------------------------------------
RenderObjectToWidgetAdapter.attachToRenderTree. (binding.dart:1165)
BuildOwner.buildScope (framework.dart:2683)
--------------------------------------------------------------------------------------------------
RenderObjectToWidgetAdapter.attachToRenderTree (binding.dart:1164)
WidgetsBinding.attachRootWidget (binding.dart:974)
WidgetsBinding.scheduleAttachRootWidget. (binding.dart:955)
_rootRun (zone.dart:1182)
_CustomZone.run (zone.dart:1093)
_CustomZone.runGuarded (zone.dart:997)
_CustomZone.bindCallbackGuarded. (zone.dart:1037)
_rootRun (zone.dart:1190)
_CustomZone.run (zone.dart:1093)
_CustomZone.bindCallback. (zone.dart:1021)
Timer._createTimer. (timer_patch.dart:18)
_Timer._runTimers (timer_impl.dart:397)
_Timer._handleMessage (timer_impl.dart:428)
_RawReceivePortImpl._handleMessage (isolate_patch.dart:168)

继续看inflateWidget

framework.dart

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);
    assert(newChild._debugLifecycleState == _ElementLifecycle.active);
    return newChild;
  }
  

inflateWidget是抽象类Element的方法,这里的参数newWidgetRenderObjectToWidgetElement.mount层层传递进去的,就是存储在RenderObjectToWidgetAdapter中的child,也就是我们在runApp时候传递的rootWidget

随着inflateWidget的执行,newWidget.createElement调用,如果newWidgetStatefulWidget就会执行StatefulElement(this);

abstract class StatefulWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatefulWidget({ Key key }) : super(key: key);

  /// Creates a [StatefulElement] to manage this widget's location in the tree.
  ///
  /// It is uncommon for subclasses to override this method.
  @override
  StatefulElement createElement() => StatefulElement(this);

如果widgetInheritedProvider,那就会执行InheritedProvidercreateElement,如果是_InheritedProviderScope,就会执行_InheritedProviderScopecreateElement。当调用newWidget.createElement时,会产生多态。

至此,我们已经清楚了,

final Element newChild = newWidget.createElement();

createElement可以创建任何Element的子类对象,下面是调用newChild.mount,由于newChild的类型不同,mount调用也是Element子类或者说实现类的mount方法,这里也解释了,mount方法就是这个时候调用的。我们通常使用的mounted的定义如下

abstract class State with Diagnosticable {
  bool get mounted => _element != null;
}

这里也层面的解释了一个问题,是现有Element对象还是先调用mount方法,答案是:先有Element对象后调用的mount方法,当我们一个widget被加到Element tree后,mounted就应该是true了

newChild.mount(this, newSlot);

Flutter Provider原理深入浅出(中)_第1张图片
image.png

如果 newChild_InheritedProviderScopeElement类型的,会有下面的堆栈:

_CreateInheritedProvider.createState (inherited_provider.dart:605)
_InheritedProviderScopeElement.performRebuild (inherited_provider.dart:424)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)

这才调用到上文提到的createState是在_InheritedProviderScopeElement类中performRebuild方法执行时候调用的,代码如下

  void performRebuild() {
    if (_firstBuild) {
      _firstBuild = false;
      _delegateState = widget.owner._delegate.createState()..element = this;
    }
    super.performRebuild();
  }

这里的widget.owner._delegate其实就是_Delegate类的子类_CreateInheritedProvider的实例,上文已经解释 ,这里不做过多说明,那随着createState的调用_CreateInheritedProviderState的对象应运而生,后面就由_delegateState进行表演了。

结语

本文所分析的都是初始化的流程,并结合上文遗留的问题进行讲解,主要通过启动流程,来搞清楚WidgetElement是如何建立关系的,接下来,我们需要聚焦的问题是:

  • 当数据发生改变的时候,视图是如何发生变化的(Provider的原理)
  • 我们通常使用的StatefulWidget视图刷新机制和Provider有什么不同
  • initState, setState的底层原理是什么

你可能感兴趣的:(Flutter Provider原理深入浅出(中))