Flutter Provider原理深入浅出(上)

1 什么是状态?什么是状态管理?

数据即为状态。从数据变化到通知界面更新的过程,我们称之为状态管理,状态管理要尽可能的把这个过程独立出来,让动态界面如同静态页面一般简单。

大到页面的路由变化,小到页面的数据发生变化,我们开发中每时每刻都离不开状态,有一位伟人曾说过,一切皆数据,那么今天就让我们从浅入深的揭开状态管理的神秘面纱。

如果还完全没有使用过Provider的同学请移步:新手入门

2 从Provider看状态管理

import 'package:flutter/material.dart';

class MyModel3 with ChangeNotifier {

  MyModel3({this.counter=0});

  int counter = 0;

  Future<void> incrementCounter() async {
//    await Future.delayed(Duration(seconds: 2));
    counter++;
    print(counter);
    notifyListeners();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    print('MyModel3 dispose');
    super.dispose();
  }
}


class ProviderDebugPage3 extends StatelessWidget {
  final String title;
  ProviderDebugPage3({this.title});
  @override
  Widget build(BuildContext context) {
    print('---provider build ---');
    return ChangeNotifierProvider(
      create: (context) => MyModel3(),
      child: Scaffold(
        appBar: AppBar(
          title: Text(this.title),
        ),
        body: Column(
          children: <Widget>[
            Consumer<MyModel3>(
              // 获取到provider提供出来的值
              builder: (context, model, child) {
                return Container(
                  margin: const EdgeInsets.only(top: 20),
                  width: MediaQuery.of(context).size.width,
                  padding: const EdgeInsets.all(20),
                  alignment: Alignment.center,
                  color: Colors.lightGreen,
                  child: Text(
                    'Model3当前是:${model.counter}',
                  ),
                );
              },
            ),
            Consumer<MyModel3>(
              // 获取到provider提供出来的值
              builder: (context, model, child) {
                return FlatButton(
                    color: Colors.tealAccent,
                    onPressed: model.incrementCounter,
                    child: Icon(Icons.add));
              },
            ),
          ],
        ),
      ),
    );
  }
}

上面是我们通常使用的ChangeNotifierProvider,这里用到了3个类ChangeNotifierProviderChangeNotifierConsumer,其中核心类是ChangeNotifierProvider,它和ChangeNotifier是观察者模式,和Consumer是生产者消费者模式,达到的目的是,即使是StatelessWidget,当数据MyModel3发生变化时,对应的UI也能一起刷新,实现了从数据变化到更新UI的自动化过程,这里并不像我们使用StatefulWidgetsetState,数据变化是自动引起UI刷新的,那么围绕核心类ChangeNotifierProvider,我们去源码一探究竟。

关系

3 ChangeNotifierProvider 源码分析

class ChangeNotifierProvider<T extends ChangeNotifier>
    extends ListenableProvider<T> {
  /// Creates a [ChangeNotifier] using `create` and automatically
  /// dispose it when [ChangeNotifierProvider] is removed from the widget tree.
  ///
  /// `create` must not be `null`.
  ChangeNotifierProvider({
    Key key,
    @required Create<T> create,
    bool lazy,
    TransitionBuilder builder,
    Widget child,
  }) : super(
          key: key,
          create: create,
          dispose: _dispose,
          lazy: lazy,
          builder: builder,
          child: child,
        );

  /// Provides an existing [ChangeNotifier].
  ChangeNotifierProvider.value({
    Key key,
    @required T value,
    TransitionBuilder builder,
    Widget child,
  }) : super.value(
          key: key,
          builder: builder,
          value: value,
          child: child,
        );

  static void _dispose(BuildContext context, ChangeNotifier notifier) {
    notifier?.dispose();
  }
}

这里ChangeNotifierProvider是一个泛型类,泛型T是继承ChangeNotifier类的,ChangeNotifierProvider初始化的时候,多加了一个_dispose方法,其余参数都传给了父类ListenableProvider,这里解释了,为什么MyModel3在页面析构的时候也会自动调用dispose,是因为当系统回调ChangeNotifierProvider_dispose方法时,_dispose里面调用了MyModel3dispose

3.1 ListenableProvider 源码分析
class ListenableProvider<T extends Listenable> extends InheritedProvider<T> {
  /// Creates a [Listenable] using [create] and subscribes to it.
  ///
  /// [dispose] can optionally passed to free resources
  /// when [ListenableProvider] is removed from the tree.
  ///
  /// [create] must not be `null`.
  ListenableProvider({
    Key key,
    @required Create<T> create,
    Dispose<T> dispose,
    bool lazy,
    TransitionBuilder builder,
    Widget child,
  })  : assert(create != null),
        super(
          key: key,
          startListening: _startListening,
          create: create,
          dispose: dispose,
          debugCheckInvalidValueType: kReleaseMode
              ? null
              : (value) {
                  if (value is ChangeNotifier) {
                    // ignore: invalid_use_of_protected_member
                    assert(!value.hasListeners, '''
The default constructor of ListenableProvider/ChangeNotifierProvider
must create a new, unused Listenable.

If you want to reuse an existing Listenable, use the second constructor:

- DO use ChangeNotifierProvider.value to provider an existing ChangeNotifier:

MyChangeNotifier variable;
ChangeNotifierProvider.value(
  value: variable,
  child: ...
)

- DON'T reuse an existing ChangeNotifier using the default constructor.

MyChangeNotifier variable;
ChangeNotifierProvider(
  create: (_) => variable,
  child: ...
)
''');
                  }
                },
          lazy: lazy,
          builder: builder,
          child: child,
        );

  /// Provides an existing [Listenable].
  ListenableProvider.value({
    Key key,
    @required T value,
    UpdateShouldNotify<T> updateShouldNotify,
    TransitionBuilder builder,
    Widget child,
  }) : super.value(
          key: key,
          builder: builder,
          value: value,
          updateShouldNotify: updateShouldNotify,
          startListening: _startListening,
          child: child,
        );

  static VoidCallback _startListening(
    InheritedContext<Listenable> e,
    Listenable value,
  ) {
    value?.addListener(e.markNeedsNotifyDependents);
    return () => value?.removeListener(e.markNeedsNotifyDependents);
  }
}

同样是泛型类,在这里又增加了一个_startListening方法,实现是的功能是:

1 订阅事件,当接受到事件时,通知Element更新UI
2 返回一个默认取消订阅的回调

相比于ChangeNotifierProvider这里我们遇到InheritedContextupdateShouldNotify,先mark下,继续往下。

3.2 InheritedProvider 源码分析
class InheritedProvider<T> extends SingleChildStatelessWidget {
  /// Creates a value, then expose it to its descendants.
  ///
  /// The value will be disposed of when [InheritedProvider] is removed from
  /// the widget tree.
  InheritedProvider({
    Key key,
    Create<T> create,
    T Function(BuildContext context, T value) update,
    UpdateShouldNotify<T> updateShouldNotify,
    void Function(T value) debugCheckInvalidValueType,
    StartListening<T> startListening,
    Dispose<T> dispose,
    this.builder,
    bool lazy,
    Widget child,
  })  : _lazy = lazy,
        _delegate = _CreateInheritedProvider(
          create: create,
          update: update,
          updateShouldNotify: updateShouldNotify,
          debugCheckInvalidValueType: debugCheckInvalidValueType,
          startListening: startListening,
          dispose: dispose,
        ),
        super(key: key, child: child);

...省略以下代码
}

相比于ListenableProvider 这里参数又增加了update,并且出现了新的属性_delegate
看定义

final _Delegate<T> _delegate;

这里之前的参数都传给了_CreateInheritedProvider类,是个内部类,也就是官方不建议我们直接使用的

class _CreateInheritedProvider<T> extends _Delegate<T> {
  _CreateInheritedProvider({
    this.create,
    this.update,
    UpdateShouldNotify<T> updateShouldNotify,
    this.debugCheckInvalidValueType,
    this.startListening,
    this.dispose,
  })  : assert(create != null || update != null),
        _updateShouldNotify = updateShouldNotify;

  final Create<T> create;
  final T Function(BuildContext context, T value) update;
  final UpdateShouldNotify<T> _updateShouldNotify;
  final void Function(T value) debugCheckInvalidValueType;
  final StartListening<T> startListening;
  final Dispose<T> dispose;

  @override
  _CreateInheritedProviderState<T> createState() =>
      _CreateInheritedProviderState();
}

class _CreateInheritedProviderState<T>
    extends _DelegateState<T, _CreateInheritedProvider<T>> {
  VoidCallback _removeListener;
  bool _didInitValue = false;
  T _value;
  _CreateInheritedProvider<T> _previousWidget;
}

至此,从ChangeNotifierProvider 传递进来的参数都存在了_CreateInheritedProvider里了,而_CreateInheritedProvider的父类是一个抽象类_Delegate

abstract class _Delegate<T> {
  _DelegateState<T, _Delegate<T>> createState();

  void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
}

abstract class _DelegateState<T, D extends _Delegate<T>> 

_DelegateState类也是泛型类,有两个泛型TD,其中D是继承_Delegate<T>的,那我们看看具体的实现类_CreateInheritedProviderState

class _CreateInheritedProviderState<T>
    extends _DelegateState<T, _CreateInheritedProvider<T>> {
  VoidCallback _removeListener;
  bool _didInitValue = false;
  T _value;
  _CreateInheritedProvider<T> _previousWidget;

  @override
  T get value {
    bool _debugPreviousIsInInheritedProviderCreate;
    bool _debugPreviousIsInInheritedProviderUpdate;

    assert(() {
      _debugPreviousIsInInheritedProviderCreate =
          debugIsInInheritedProviderCreate;
      _debugPreviousIsInInheritedProviderUpdate =
          debugIsInInheritedProviderUpdate;
      return true;
    }());

    if (!_didInitValue) {
      _didInitValue = true;
      if (delegate.create != null) {
        assert(debugSetInheritedLock(true));
        try {
          assert(() {
            debugIsInInheritedProviderCreate = true;
            debugIsInInheritedProviderUpdate = false;
            return true;
          }());
          _value = delegate.create(element);
        } finally {
          assert(() {
            debugIsInInheritedProviderCreate =
                _debugPreviousIsInInheritedProviderCreate;
            debugIsInInheritedProviderUpdate =
                _debugPreviousIsInInheritedProviderUpdate;
            return true;
          }());
        }
        assert(debugSetInheritedLock(false));

        assert(() {
          delegate.debugCheckInvalidValueType?.call(_value);
          return true;
        }());
      }
      if (delegate.update != null) {
        try {
          assert(() {
            debugIsInInheritedProviderCreate = false;
            debugIsInInheritedProviderUpdate = true;
            return true;
          }());
          _value = delegate.update(element, _value);
        } finally {
          assert(() {
            debugIsInInheritedProviderCreate =
                _debugPreviousIsInInheritedProviderCreate;
            debugIsInInheritedProviderUpdate =
                _debugPreviousIsInInheritedProviderUpdate;
            return true;
          }());
        }

        assert(() {
          delegate.debugCheckInvalidValueType?.call(_value);
          return true;
        }());
      }
    }

    element._isNotifyDependentsEnabled = false;
    _removeListener ??= delegate.startListening?.call(element, _value);
    element._isNotifyDependentsEnabled = true;
    assert(delegate.startListening == null || _removeListener != null);
    return _value;
  }

  @override
  void dispose() {
    super.dispose();
    _removeListener?.call();
    if (_didInitValue) {
      delegate.dispose?.call(element, _value);
    }
  }

  @override
  void build({bool isBuildFromExternalSources}) {
    var shouldNotify = false;
    // Don't call `update` unless the build was triggered from `updated`/`didChangeDependencies`
    // otherwise `markNeedsNotifyDependents` will trigger unnecessary `update` calls
    if (isBuildFromExternalSources &&
        _didInitValue &&
        delegate.update != null) {
      final previousValue = _value;

      bool _debugPreviousIsInInheritedProviderCreate;
      bool _debugPreviousIsInInheritedProviderUpdate;
      assert(() {
        _debugPreviousIsInInheritedProviderCreate =
            debugIsInInheritedProviderCreate;
        _debugPreviousIsInInheritedProviderUpdate =
            debugIsInInheritedProviderUpdate;
        return true;
      }());
      try {
        assert(() {
          debugIsInInheritedProviderCreate = false;
          debugIsInInheritedProviderUpdate = true;
          return true;
        }());
        _value = delegate.update(element, _value);
      } finally {
        assert(() {
          debugIsInInheritedProviderCreate =
              _debugPreviousIsInInheritedProviderCreate;
          debugIsInInheritedProviderUpdate =
              _debugPreviousIsInInheritedProviderUpdate;
          return true;
        }());
      }

      if (delegate._updateShouldNotify != null) {
        shouldNotify = delegate._updateShouldNotify(previousValue, _value);
      } else {
        shouldNotify = _value != previousValue;
      }

      if (shouldNotify) {
        assert(() {
          delegate.debugCheckInvalidValueType?.call(_value);
          return true;
        }());
        if (_removeListener != null) {
          _removeListener();
          _removeListener = null;
        }
        _previousWidget?.dispose?.call(element, previousValue);
      }
    }

    if (shouldNotify) {
      element._shouldNotifyDependents = true;
    }
    _previousWidget = delegate;
    return super.build(isBuildFromExternalSources: isBuildFromExternalSources);
  }

  @override
  bool get hasValue => _didInitValue;
}

因为T get value还没用到,我们focus在build,由于父类_DelegateState是抽象类,这里重写了build方法,这里用到了两个属性,delegateelement,都是父类中定义的,delegate也是element中取到的

abstract class _DelegateState<T, D extends _Delegate<T>> {
  _InheritedProviderScopeElement<T> element;

  T get value;

  D get delegate => element.widget.owner._delegate as D;

  bool get hasValue;

  bool debugSetInheritedLock(bool value) {
    return element._debugSetInheritedLock(value);
  }

  bool willUpdateDelegate(D newDelegate) => false;

  void dispose() {}

  void debugFillProperties(DiagnosticPropertiesBuilder properties) {}

  void build({@required bool isBuildFromExternalSources}) {}
}

那我们看看element是怎么来的,首先,类型是_InheritedProviderScopeElement<T>,我们找到创建对象的地方:_InheritedProviderScope中有个createElement方法可以返回这样的element,但从dart代码上我们没追踪到谁调用了createElement,我们先mark一下,谁调用了createElement

class _InheritedProviderScope<T> extends InheritedWidget {
  const _InheritedProviderScope({
    this.owner,
    @required Widget child,
  }) : super(child: child);

  final InheritedProvider<T> owner;

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) {
    return false;
  }

  @override
  _InheritedProviderScopeElement<T> createElement() {
    return _InheritedProviderScopeElement<T>(this);
  }
}
class _InheritedProviderScopeElement<T> extends InheritedElement
    implements InheritedContext<T> {
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
      : super(widget);

  bool _shouldNotifyDependents = false;
  bool _debugInheritLocked = false;
  bool _isNotifyDependentsEnabled = true;
  bool _firstBuild = true;
  bool _updatedShouldNotify = false;
  bool _isBuildFromExternalSources = false;
  _DelegateState<T, _Delegate<T>> _delegateState;

  @override
  _InheritedProviderScope<T> get widget =>
      super.widget as _InheritedProviderScope<T>;
...以下代码省略
}

说到这个_InheritedProviderScope类,存在着继承关系:_InheritedProviderScope->InheritedWidget>ProxyWidget->Widget,本质上是一个Widget,在构造的时候,外面传入了owner,也就是InheritedProvider,这样就在Widget里面持有了InheritedProvider,那在创建_InheritedProviderScopeElement时传入了this,也就把InheritedProvider带给了InheritedElement(_InheritedProviderScopeElement的父类,继承关系:_InheritedProviderScopeElement->InheritedElement->ProxyElement->ComponentElement->Element->DiagnosticableTree),所以本质还是Element,如果对WidgetElement还不太清楚的,可以参考这篇文章,实际视图的刷新逻辑都是在Element中,本节我们暂不深入分析视图刷新的逻辑,先回到上说的_CreateInheritedProviderState另外一个属性delegate

D get delegate => element.widget.owner._delegate as D;

这里我们看到,之前element持有了_InheritedProviderScopewidgetwidgetownerInheritedProviderelement.widget.owner._delegate就是InheritedProvider的属性_delegate,是通过_CreateInheritedProvider创建的,这里就整个都串起来了。

image.png

上面都是对ChangeNotifierProvider进行的深入分析,我们留下几个疑问:
1、InheritedContextupdateShouldNotify是做什么的
2、 谁调用了createElement
带着问题我们开启Consumer的源码分析

4 Consumer 源码分析

ConsumerChangeNotifierProvider是生产者和消费者模式,那生产的是什么?消费的又是什么呢?

class Consumer<T> extends SingleChildStatelessWidget {
  /// {@template provider.consumer.constructor}
  /// Consumes a [Provider<T>]
  /// {@endtemplate}
  Consumer({
    Key key,
    @required this.builder,
    Widget child,
  })  : assert(builder != null),
        super(key: key, child: child);

  /// {@template provider.consumer.builder}
  /// Build a widget tree based on the value from a [Provider<T>].
  ///
  /// Must not be `null`.
  /// {@endtemplate}
  final Widget Function(BuildContext context, T value, Widget child) builder;

  @override
  Widget buildWithChild(BuildContext context, Widget child) {
    return builder(
      context,
      Provider.of<T>(context),
      child,
    );
  }
}

Consumer是一个Widget,这个没问题,我们在写的时候,就是把Consumer当成widget用的,Consumer的参数都传递到了父类SingleChildStatelessWidgetSingleChildStatelessWidget是一个抽象类,里面存储了传入的child

abstract class SingleChildStatelessWidget extends StatelessWidget
    implements SingleChildWidget {
  /// Creates a widget that has exactly one child widget.
  const SingleChildStatelessWidget({Key key, Widget child})
      : _child = child,
        super(key: key);

  final Widget _child;

  /// A [build] method that receives an extra `child` parameter.
  ///
  /// This method may be called with a `child` different from the parameter
  /// passed to the constructor of [SingleChildStatelessWidget].
  /// It may also be called again with a different `child`, without this widget
  /// being recreated.
  Widget buildWithChild(BuildContext context, Widget child);

  @override
  Widget build(BuildContext context) => buildWithChild(context, _child);

  @override
  SingleChildStatelessElement createElement() {
    return SingleChildStatelessElement(this);
  }
}

并且Consumer重写了抽象类SingleChildStatelessWidget定义的buildWithChild

buildWithChild这个也是系统调用的方法,buildWithChild回调的时候,会接收一个child参数,这个参数可能和SingleChildStatelessWidget的构造函数传递进去的不一样,当控件没有被重新创建的时候也会再次调用并传递不同的child,大致的意思就是,不管你传进来的child是否变化,buildWithChild都可能带着新的child再次回调,buildWithChild的实现里返回的是一个builder,里面的参数value传递的是Provider.of<T>(context),这就和Provider建立起关系了,传进来的builder是用来构建一个widget tree的,这个值一定不能为null,大概理解下就是buildWithChild是用Consumer传进来的builder构建并返回一个新的Widget,使用的参数是系统回调child但这个child我们通常没有用,最终这个builder的执行将会调用下面红色箭头处的代码
小结:系统调用buildWithChildbuildWithChild调用builder来将widget tree变成element tree。

image.png

而传递的model就是Provider.of<T>(context),这也就是为什么我们通常用类似下面的写法也可以得到相同的效果

class ProviderDebugPage1 extends StatelessWidget {
  final String title;
  ProviderDebugPage1({this.title});
  @override
  Widget build(BuildContext context) {
    print('---provider build ---');
    return Scaffold(
      appBar: AppBar(
        title: Text(this.title),
      ),
      body: Column(
        children: <Widget>[
          Builder(
            builder: (context) {
              // 获取到provider提供出来的值
              MyModel1 _model = Provider.of<MyModel1>(context, listen: false);
              return Container(
                  margin: const EdgeInsets.only(top: 20),
                  width: MediaQuery.of(context).size.width,
                  padding: const EdgeInsets.all(20),
                  alignment: Alignment.center,
                  color: Colors.lightBlueAccent,
                  child: Text('不监听Model1当前是:${_model.counter}'));
            },
          ),
          Consumer<MyModel1>(
            // 获取到provider提供出来的值
            builder: (context, model, child) {
              return Container(
                margin: const EdgeInsets.only(top: 20),
                width: MediaQuery.of(context).size.width,
                padding: const EdgeInsets.all(20),
                alignment: Alignment.center,
                color: Colors.lightGreen,
                child: Text('Model1当前是:${model.counter}',
                ),
              );
            },
          ),
          Consumer<MyModel2>(
            // 获取到provider提供出来的值
            builder: (context, model, child) {
              return FlatButton(
                  color: Colors.tealAccent,
                  onPressed:model.incrementCounter,
                  child: Icon(Icons.add));
            },
          ),
    );
  }
}

原因就是Consumer里面封装了Provider.of,简单说就是,Consumer内置了builder的功能,并且Model对象被主动回传了。好了,是时候看一下非常重要的Provider.of<T>(context)

class Provider<T> extends InheritedProvider<T> {
  /// Creates a value, store it, and expose it to its descendants.
  ///
  /// The value can be optionally disposed using [dispose] callback.
  /// This callback which will be called when [Provider] is unmounted from the
  /// widget tree.
  Provider({
    Key key,
    @required Create<T> create,
    Dispose<T> dispose,
    bool lazy,
    TransitionBuilder builder,
    Widget child,
  })  : assert(create != null),
        super(
          key: key,
          lazy: lazy,
          builder: builder,
          create: create,
          dispose: dispose,
          debugCheckInvalidValueType: kReleaseMode
              ? null
              : (T value) =>
                  Provider.debugCheckInvalidValueType?.call<T>(value),
          child: child,
        );

  /// Expose an existing value without disposing it.
  ///
  /// {@template provider.updateshouldnotify}
  /// `updateShouldNotify` can optionally be passed to avoid unnecessarily
  /// rebuilding dependents when [Provider] is rebuilt but `value` did not change.
  ///
  /// Defaults to `(previous, next) => previous != next`.
  /// See [InheritedWidget.updateShouldNotify] for more information.
  /// {@endtemplate}
  Provider.value({
    Key key,
    @required T value,
    UpdateShouldNotify<T> updateShouldNotify,
    TransitionBuilder builder,
    Widget child,
  })  : assert(() {
          Provider.debugCheckInvalidValueType?.call<T>(value);
          return true;
        }()),
        super.value(
          key: key,
          builder: builder,
          value: value,
          updateShouldNotify: updateShouldNotify,
          child: child,
        );

  /// Obtains the nearest [Provider<T>] up its widget tree and returns its
  /// value.
  ///
  /// If [listen] is `true`, later value changes will trigger a new
  /// [State.build] to widgets, and [State.didChangeDependencies] for
  /// [StatefulWidget].
  ///
  /// `listen: false` is necessary to be able to call `Provider.of` inside
  /// [State.initState] or the `create` method of providers like so:
  ///
  /// ```dart
  /// Provider(
  ///   create: (context) {
  ///     return Model(Provider.of<Something>(context, listen: false)),
  ///   },
  /// )
  /// ```
  static T of<T>(BuildContext context, {bool listen = true}) {
    assert(context != null);
    assert(
      context.owner.debugBuilding ||
          listen == false ||
          debugIsInInheritedProviderUpdate,
      '''
Tried to listen to a value exposed with provider, from outside of the widget tree.

This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.

To fix, write:
Provider.of<$T>(context, listen: false);

It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.

The context used was: $context
''',
    );

    final inheritedElement = _inheritedElementOf<T>(context);

    if (listen) {
      context.dependOnInheritedElement(inheritedElement);
    }

    return inheritedElement.value;
  }

  static _InheritedProviderScopeElement<T> _inheritedElementOf<T>(
    BuildContext context,
  ) {
    assert(context != null, '''
Tried to call context.read/watch/select or similar on a `context` that is null.

This can happen if you used the context of a StatefulWidget and that
StatefulWidget was disposed.
''');
    assert(
      _debugIsSelecting == false,
      'Cannot call context.read/watch/select inside the callback of a context.select',
    );
    assert(
      T != dynamic,
      '''
Tried to call Provider.of<dynamic>. This is likely a mistake and is therefore
unsupported.

If you want to expose a variable that can be anything, consider changing
`dynamic` to `Object` instead.
''',
    );
    _InheritedProviderScopeElement<T> inheritedElement;

    if (context.widget is _InheritedProviderScope<T>) {
      // An InheritedProvider<T>'s update tries to obtain a parent provider of
      // the same type.
      context.visitAncestorElements((parent) {
        inheritedElement = parent.getElementForInheritedWidgetOfExactType<
            _InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>;
        return false;
      });
    } else {
      inheritedElement = context.getElementForInheritedWidgetOfExactType<
          _InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>;
    }

    if (inheritedElement == null) {
      throw ProviderNotFoundException(T, context.widget.runtimeType);
    }

    return inheritedElement;
  }
...下面省略debugCheckInvalidValueType方法
}

尝试翻译下,向上查找最近的一个使用Provider植入的T类型的value,简单来说就是顺着widget数查找最近的数据类型是T的数据,并返回这个数据,通常情况下,我们想要共享数据,会把数据存放在InheritedWidget中,因为Flutter 开发中,程序员只能拿到Widget,通常不会直接操作Element,但Element才是真正决定视图显示的,所以,Element通过持有Widget来间接操作数据,具体原理可以参考这篇文章。调用Provider.of<T>(context)时候有个listen参数,默认是true,会调用dependOnInheritedElement,它需要一个_inheritedElementOf参数,这里会访问当前节点的parent:context.visitAncestorElements,前提是当前widget_InheritedProviderScope类型的,也就是数据节点,_InheritedProviderScope我们第一次提到是在说createElement方法的时候,继续看getElementForInheritedWidgetOfExactType,已经来到核心代码了

  InheritedElement getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
    assert(_debugCheckStateIsActiveForAncestorLookup());
    final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
    return ancestor;
  }

_inheritedWidgets取出Key为泛型T的对象的数据,那我们看看是在哪里存储的吧

class InheritedElement extends ProxyElement {
  /// Creates an element that uses the given widget as its configuration.
  InheritedElement(InheritedWidget widget) : super(widget);

  @override
  InheritedWidget get widget => super.widget as InheritedWidget;

  final Map<Element, Object> _dependents = HashMap<Element, Object>();

  @override
  void _updateInheritance() {
    assert(_active);
    final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;
    if (incomingWidgets != null)
      _inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets);
    else
      _inheritedWidgets = HashMap<Type, InheritedElement>();
    _inheritedWidgets[widget.runtimeType] = this;
  }

  下面是Element类的
  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;
    final Key key = widget.key;
    if (key is GlobalKey) {
      key._register(this);
    }
    _updateInheritance();
    assert(() {
      _debugLifecycleState = _ElementLifecycle.active;
      return true;
    }());

  void activate() {
    assert(_debugLifecycleState == _ElementLifecycle.inactive);
    assert(widget != null);
    assert(owner != null);
    assert(depth != null);
    assert(!_active);
    final bool hadDependencies = (_dependencies != null && _dependencies.isNotEmpty) || _hadUnsatisfiedDependencies;
    _active = true;
    // We unregistered our dependencies in deactivate, but never cleared the list.
    // Since we're going to be reused, let's clear our list now.
    _dependencies?.clear();
    _hadUnsatisfiedDependencies = false;
    _updateInheritance();
    assert(() {
      _debugLifecycleState = _ElementLifecycle.active;
      return true;
    }());
    if (_dirty)
      owner.scheduleBuildFor(this);
    if (hadDependencies)
      didChangeDependencies();
  }
  }

说明在mountactivate时候都会用,因为子类InheritedElement重写了_updateInheritance方法,所以当系统调用mount或者activate方法的时候,自然来到了InheritedElement类的实现,至于这里系统什么时机调用mount我们还是先mark下。这里有一个需要特别注意的,_inheritedWidgets这个是定义在Element类里的字典,但是字典的Key是泛型,Value是InheritedElement

Map<Type, InheritedElement> _inheritedWidgets;

在存储的时候,

_inheritedWidgets[widget.runtimeType] = this;

把自己存在了父类的_inheritedWidgets中,但如果父类对象已经存储了T类型的InheritedElement,那就直接复用这个,如果没有就创建它,简单说就是,获取parent值,并注册自身。初始化的时候将InheritedElement类的对象存储在Element类的_inheritedWidgets中,这样在获取的时候,就可以通过parent .getElementForInheritedWidgetOfExactType拿到,通过调试代码,我们发现_InheritedProviderScope没有用到,因为这些节点并不是_InheritedProviderScopeElement类型的,context类型是SingleChildStatelessElementcontext.widget的类型是Consumer<T>

获取的inheritedElement

context

所以,不管是否是_InheritedProviderScopeElement节点,都可以拿到对应的inheritedElement节点,冥冥之中,我们似乎感觉,一直被系统支配,汇总下我们的问题:

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

这一切的答案都在Element中,由于篇幅有限,我们带着这些问题,通过代码调试,在下一篇来一探究竟

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容