前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter Provider-状态管理源码解析

Flutter Provider-状态管理源码解析

作者头像
用户4458175
修改2022-04-15 16:23:22
7280
修改2022-04-15 16:23:22
举报
文章被收录于专栏:andy的小窝

这是一篇Provider的源码分析。我们从一个简单的例子开始分析,看provider怎么实现的状态管理。话不多说进入主题吧。

代码语言:javascript
复制
class Counter with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

首先我们创建自己的继承于ChangeNotifier的状态类CounterChangeNotifier实现Listenable的方法。监听者通过addListener注册监听,当我们调用notifyListeners会触发监听者的方法回调。

接着我们创建ChangeNotifierProvider,实现对Counter状态监听。

代码语言:javascript
复制
ChangeNotifierProvider(
  create: (context) => Counter(),
  builder: (context, child) {
    return Consumer<Counter>(
      builder: (context, counter, child) {
        return Text('${counter.count}');
      },
    );
  },
)

ChangeNotifierProvider继承自ListenableProvider,有两个构造方法,一个是默认的构造方法,一个是.value构造方法。通过create创作的会传递静态_dispose方法即自动管理create和dispose。.value传递一个已有的ChangeNotifier对象。的需要自己管理ChangeNotifierProvider的释放。(ps: 这里也是很多同学遇到value构造的ChangeNotifier不会随生命周期调用dispose问题)

代码语言:javascript
复制
class ChangeNotifierProvider<T extends ChangeNotifier?>
    extends ListenableProvider<T> {
  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();
  }
}

接着往上走 ListenableProvider 继承自InheritedProvider,这里同样是一个create和value的构造方法,向父类传递一个开始监听的方法_startListening_startListening实际就是ChangeNotifier监听刷新的实现,我们记住这个方法,后面会用到。

代码语言:javascript
复制
class ListenableProvider<T extends Listenable?> extends InheritedProvider<T> {
  ListenableProvider({
    Key? key,
    required Create<T> create,
    Dispose<T>? dispose,
    bool? lazy,
    TransitionBuilder? builder,
    Widget? child,
  }) : super(
          key: key,
          startListening: _startListening,
          create: create,
          dispose: dispose,
          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 e,
    Listenable? value,
  ) {
    value?.addListener(e.markNeedsNotifyDependents);
    return () => value?.removeListener(e.markNeedsNotifyDependents);
  }
}

接着往上走 InheritedProvider 继承自SingleChildStatelessWidgetSingleChildStatelessWidget是Provider为了方便编码而导入的库,可以简化开发。可以见库介绍。我们在这里关注buildWithChild方法即可。

InheritedProvider同样有create和value的构造方法。在构造方法创建不同的_Delegate_Delegate<T>是类似与Stateful Widget的一个类,createState可以创建对应的state对象。这里有两种类型的Delegate,_CreateInheritedProvider_ValueInheritedProvider对应create和value的构造方法。在这里我们关注_CreateInheritedProvider的实现。创建_CreateInheritedProvider_Delegate会传递create,startListening, dispose等方法。接下来就是实现Provider共享数据的关键,也就是InheriedWidget出场的时候啦。buildWithChild创建了_InheritedProviderScope并且将InheritedProvider作为owner参数传递过去。我们切换看下_InheritedProviderScope实现。

代码语言:javascript
复制
// 代码有部分省略
class InheritedProvider<T> extends SingleChildStatelessWidget {
  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);

  /// Expose to its descendants an existing value,
  InheritedProvider.value({
    Key? key,
    required T value,
    UpdateShouldNotify<T>? updateShouldNotify,
    StartListening<T>? startListening,
    bool? lazy,
    this.builder,
    Widget? child,
  })  : _lazy = lazy,
        _delegate = _ValueInheritedProvider(
          value: value,
          updateShouldNotify: updateShouldNotify,
          startListening: startListening,
        ),
        super(key: key, child: child);

  final _Delegate<T> _delegate;
  final bool? _lazy;

  @override
  Widget buildWithChild(BuildContext context, Widget? child) {
    return _InheritedProviderScope<T?>(
      owner: this,
      // ignore: no_runtimetype_tostring
      debugType: kDebugMode ? '$runtimeType' : '',
      child: builder != null
          ? Builder(
              builder: (context) => builder!(context, child),
            )
          : child!,
    );
  }
}

_InheritedProviderScope是一个InheritedWidget,将上面传递过来的InheritedProvider(owner)对象作为我们的inherited对象。我们知道updateShouldNotify是控制InheritedWidget是否刷新的。这里updateShouldNotify always return false是因为_InheritedProviderScope重写了InheritedWidgetcreateElement。由element自行管理notifyClients.

代码语言:javascript
复制
class _InheritedProviderScope<T> extends InheritedWidget {
  const _InheritedProviderScope({
    required this.owner,
    required this.debugType,
    required Widget child,
  })  : assert(null is T),
        super(child: child);

  final InheritedProvider<T> owner;
  final String debugType;

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

  @override
  _InheritedProviderScopeElement<T> createElement() {
    return _InheritedProviderScopeElement<T>(this);
  }
}

_InheritedProviderScopeElement继承自InheritedElement,在performRebuild中,我们初始化了_delegateState并传递element给_Delegate。用于将InheritedElement标记脏。在下一帧build方法调用notifyClients(widget)通知刷新。

代码语言:javascript
复制
// 代码有部分省略
class _InheritedProviderScopeElement<T> extends InheritedElement
    implements InheritedContext<T> {
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
      : super(widget);

  static int _nextProviderId = 0;

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

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

  @override
  Widget build() {
    if (widget.owner._lazy == false) {
      value; // this will force the value to be computed.
    }
    _delegateState.build(
      isBuildFromExternalSources: _isBuildFromExternalSources,
    );
    _isBuildFromExternalSources = false;
    if (_shouldNotifyDependents) {
      _shouldNotifyDependents = false;
      notifyClients(widget);
    }
    return super.build();
  }

  @override
  void markNeedsNotifyDependents() {
    if (!_isNotifyDependentsEnabled) {
      return;
    }

    markNeedsBuild();
    _shouldNotifyDependents = true;
  }

  @override
  void unmount() {
    _delegateState.dispose();
    ...
  }

  @override
  T get value => _delegateState.value;
}

在_Delegate _CreateInheritedProviderState中value为Counter状态类,当获取value时会判断是否初始化,调用我们上面传入的create初始化状态类。还记得我们上面不断传递的startListening吗?也是在获取value这里创建了对Counter(ChangeNotifier)的监听。_removeListener ??= delegate.startListening?.call(element!, _value as T)

代码语言:javascript
复制
// 代码有部分省略
class _CreateInheritedProviderState<T>
    extends _DelegateState<T, _CreateInheritedProvider<T>> {
  VoidCallback? _removeListener;
  bool _didInitValue = false;
  T? _value;
  _CreateInheritedProvider<T>? _previousWidget;
  FlutterErrorDetails? _initError;

  @override
  T get value {
    ...
    if (!_didInitValue) {
      _didInitValue = true;
      if (delegate.create != null) {
        ...
        _value = delegate.create!(element!);
        ...
      }
      ...
    }

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

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

上面可知,dispose由element的unmout驱动,那Value的调用又在哪呢?没错就是上面用到的Consumer组件。Consumer实际是对Provider使用的封装。buildWithChild使用了Provider.of(context),我们看下这个实现,通过_inheritedElementOf获取到_InheritedProviderScopeElement,_InheritedProviderScopeElement的Value指向Delegate的value。listen参数用于是否监听刷新,实际就是用dependOnInheritedWidgetOfExactType将组件加入InheritedWidget的监听中。

代码语言:javascript
复制
// 代码有部分省略
class Provider<T> extends InheritedProvider<T> {
  static T of<T>(BuildContext context, {bool listen = true}) {
    ...

    final inheritedElement = _inheritedElementOf<T>(context);

    if (listen) {
      // bind context with the element
      // We have to use this method instead of dependOnInheritedElement, because
      // dependOnInheritedElement does not support relocating using GlobalKey
      // if no provider were found previously.
      context.dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>();
    }

    final value = inheritedElement?.value;

    ...

    return value as T;
  }

  static _InheritedProviderScopeElement<T?>? _inheritedElementOf<T>(
      BuildContext context,
      ) {
    ...
  }
}

至此整个Provider的刷新链路就整理完毕啦~。简单总结一下:Provider.of(context)通过_inheritedElementOf获取到element,element.value实现了Counter状态类的初始化、监听。当Counter调用notifyListeners,会触发element的rebuild,element会notifyClients通知使用了dependOnInheritedWidgetOfExactType的context刷新。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年4月13日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档