Flutter中Provider的原理剖析

平安喜乐

Provider的使用范例

在pubspec.yaml中引入provider插件后执行命令flutter pub get;

dependencies:
  provider: ^6.0.5

同Stream、BLoC一样,Provider的基础结构也可分为logic、state、view三层;

首先定义state层,初始化需state实例以及相关数据;

class ProviderDemoState {
 
  late int count;
 
  ProviderDemoState() {
    count = 0;
  }
}

provider层,等同于logic层,用于绑定state层以及实现对state层数据的更新操作;

import 'provider_demo_state.dart';
 
class ProviderDemoProvider extends ChangeNotifier {
  final state = ProviderDemoState();
 
  void increment() {
    state.count++;
    notifyListeners();
  }
}

view层,通过ChangeNotifierProvider定义状态管理的入口,在相应的widget中获取provider,通过Consumer包裹需要刷新的控件完成刷新;

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'provider_demo_provider.dart';
 
class ProviderDemoPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (BuildContext context) => ProviderDemoProvider(),
      builder: (context, child) => _buildPage(context),
    );
  }
 
  Widget _buildPage(BuildContext context) {
    final provider = context.read<ProviderDemoProvider>();
    final state = provider.state;
 
    return Scaffold(
      appBar: AppBar(title: Text('Provider-范例')),
      body: Center(
        child: Consumer<ProviderDemoProvider>(
          builder: (context, provider, child) {
            return Text(
              'You have pushed the button this many times: ${state.count} ',
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => provider.increment(),
        child: Icon(Icons.add),
      ),
    );
  }
}

这样,就可以通过provider实现一个简单的点击按钮自动刷新页面文字内容的功能了。

前置知识

ChangeNotifier的使用

通常情况下,ChangeNotifier都是结合ChangeNotifierProvider在provider框架中使用,我们在provider层(logic层)定义的用来操作state层数据变化的类就是继承自ChangeNotifier,但实际上,ChangeNotifier也是可以单独使用的,例如TextFiled中的TextEditingController就是继承自ValueNotifier(ChangeNotifier的子类),通过监听每一次对TextEditingController.value的赋值操作,加以相应的逻辑判断,最终通过setState()方法实现控件的刷新。

我们看下ValueNotifier的源码:

class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {
  ValueNotifier(this._value);
  @override
  T get value => _value;
  T _value;
  set value(T newValue) {
    if (_value == newValue)
      return;
    _value = newValue;
    notifyListeners();
  }
 
  @override
  String toString() => '${describeIdentity(this)}($value)';
}

由源码可知,每次对ValueNotifier中的value(TextEditingController.value)进行set操作是,都会判断value的值是否有变化,如果有变化则调用notifyListeners()方法通知刷新;

我们可以仿写TextFiled的刷新逻辑自定义一个能实现自动刷新的组件:

先通过继承ChangeNotifier实现控制器类;

class TestNotifierController extends ChangeNotifier {
  String _value = '0';
 
  String get value => _value;
 
  set value(String newValue) {
    if (_value == newValue) return;
    _value = newValue;
    notifyListeners();
  }
}

定义与控制器相搭配的widget;

class TestNotifierWidget extends StatefulWidget {
  const TestNotifierWidget({
    Key? key,
    this.controller,
  }) : super(key: key);
 
  final TestNotifierController? controller;
 
  @override
  _TestNotifierState createState() => _TestNotifierState();
}
 
class _TestNotifierState extends State<TestNotifierWidget> {
  @override
  void initState() {
    ///添加回调 value改变时,自动触发回调内容
    widget.controller?.addListener(_change);
    super.initState();
  }
 
  @override
  Widget build(BuildContext context) {
    return Text(
      widget.controller?.value ?? '初始值为空',
      style: TextStyle(fontSize: 30.0),
    );
  }
 
  ///被触发的回调
  void _change() {
    setState(() {});
  }
}

以上便完成了一个 可以通过改变控制器的数据,完成自动刷新的widget组件。

控件的使用:

class TestNotifierPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final controller = TestNotifierController();
    var count = 0;
 
    return Scaffold(
      appBar: AppBar(title: Text('ChangeNotifier使用演示')),
      body: Center(
        child: TestNotifierWidget(controller: controller),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          count += 1;
          controller.value = '数值变化:${count.toString()}';
        },
        child: Icon(Icons.add),
      ),
    );
  }
}
  • 点击按钮,在onPressed()方法中改变控制器的数据,以达到自动刷新的效果。

Function call()

在源码中,可以看到大量的XXX.call()这样的方法调用的写法,实际上XXX.call()等效于XXX();

某些场景下,使用XXX.call()的方式可以帮助我们简化很多代码,例如:

class TestWidget extends StatelessWidget {
  const TestWidget({
    Key? key,
    this.onTap,
    this.onBack,
  }) : super(key: key);
 
  final VoidCallback? onTap;
 
  final VoidCallback? onBack;
 
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        if (onTap != null) {
          onTap!();
        }
        if (onBack != null) {
          onBack!();
        }
      },
      child: Container(),
    );
  }
}
  • 该场景下的onTap()、onBack()方法,如果不做判空操作且外部未实现对应方法的情况下,调用方法会报出异常;

使用XXX.call()的方式后,可以直接省略if判空的操作了;

class TestWidget extends StatelessWidget {
  const TestWidget({
    Key? key,
    this.onTap,
    this.onBack,
  }) : super(key: key);
 
  final VoidCallback? onTap;
 
  final VoidCallback? onBack;
 
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        onTap?.call();
        onBack?.call();
      },
      child: Container(),
    );
  }
}

Provider的刷新机制-主流程

我们继承自ChangeNotifier的类,都是通过ChangeNotifierProvider传入到的Provider框架内部的,所以ChangeNotifierProvider相当于是框架的入口;

ChangeNotifierProvider的源码如下:

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,
        );
 
  ...
 
  static void _dispose(BuildContext context, ChangeNotifier? notifier) {
    notifier?.dispose();
  }
}
  • 可以看到,ChangeNotifierProvider内部定义了一个_dispose()方法,方法销毁了传入的ChangeNotifier(XXXProvider的父类)实例,并将_dispose()方法传递给父类(ListenableProvider);

ListenableProvider的源码:


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,
        ); 
 
  ...
 
  static VoidCallback _startListening(InheritedContext e, Listenable? value,) {
    value?.addListener(e.markNeedsNotifyDependents);
    return () => value?.removeListener(e.markNeedsNotifyDependents);
  }
}
  • ListenableProvider内部定义了一个_startListening()方法,在方法内部对传入的Listenable实例添加了监听,_startListening()方法被传递给了父类(InheritedProvider);

InheritedProvider的源码:

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);
 
  ...
 
  final _Delegate<T> _delegate;
  final bool? _lazy;
  final TransitionBuilder? builder;
 
  ...
 
  @override
  Widget buildWithChild(BuildContext context, Widget? child) {
    ...
    return _InheritedProviderScope<T>(
      owner: this,
      debugType: kDebugMode ? '$runtimeType' : '',
      child: builder != null
          ? Builder(
              builder: (context) => builder!(context, child),
            )
          : child!,
    );
  }
}
  • InheritedProvider继承自SingleChildStatelessWidget(StatelessWidget的子类);
  • buildWithChild()方法中返回了一个_InheritedProviderScope实例;
  • SingleChildStatelessWidget中的buildWithChild()方法就相当于StatelessWidget中的build()方法;

_InheritedProviderScope的源码:

class _InheritedProviderScope<T> extends InheritedWidget {
  const _InheritedProviderScope({
    required this.owner,
    required this.debugType,
    required Widget child,
  }) : 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);
  }
}
  • _InheritedProviderScope继承自InheritedWidget,所以在widget创建的时候就会调用其自身的createElement()方法;
  • createElement()方法内部返回了一个_InheritedProviderScopeElement实例;

_InheritedProviderScopeElement的源码:

abstract class InheritedContext<T> extends BuildContext {
  T get value;
 
  void markNeedsNotifyDependents();
 
  bool get hasValue;
}
 
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
      : super(widget);
 
  ...
 
  @override
  void mount(Element? parent, dynamic newSlot) {
    ...
  }
 
  @override
  _InheritedProviderScope<T> get widget => super.widget as _InheritedProviderScope<T>;
 
  @override
  void reassemble() {
    ...
  }
 
  @override
  void updateDependencies(Element dependent, Object? aspect) {
    ...
  }
 
  @override
  void notifyDependent(InheritedWidget oldWidget, Element dependent) {
    ...
  }
 
  @override
  void performRebuild() {
    ...
  }
 
  @override
  void update(_InheritedProviderScope<T> newWidget) {
    ...
  }
 
  @override
  void updated(InheritedWidget oldWidget) {
    ...
  }
 
  @override
  void didChangeDependencies() {
    ...
  }
 
  @override
  Widget build() {
    ...
  }
 
  @override
  void unmount() {
    ...
  }
 
  @override
  bool get hasValue => _delegateState.hasValue;
 
  @override
  void markNeedsNotifyDependents() {
    ...
  }
 
  bool _debugSetInheritedLock(bool value) {
    ...
  }
 
  @override
  T get value => _delegateState.value;
 
  @override
  InheritedWidget dependOnInheritedElement(InheritedElement ancestor, {Object? aspect,}) {
    ...
  }
 
  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    ...
  }
}
  • 这里省略了_InheritedProviderScopeElement中方法的实现(不然代码太多了);
  • _InheritedProviderScopeElement继承自InheritedContext,而InheritedContext继承自BuildContext;
  • BuildContext是一个抽象类,也就是说_InheritedProviderScopeElement中实现了BuildContext中所有的抽象方法;
  • BuildContext中的抽象方法多与控件的生命周期挂钩(如performRebuild()、reassemble());

由上面流程可知,ChangeNotifierProvider在初始化时,经过逐层的回溯,最终会实例化一个_InheritedProviderScopeElement对象(BuildContext的实现),同时_InheritedProviderScopeElement内部的生命周期也被触发;由于Provider添加监听和刷新的逻辑都和_InheritedProviderScopeElement有关,因此,可以说在ChangeNotifierProvider在初始化时,ChangeNotifierProvider的子组件就拥有了状态管理的能力。

ChangeNotifierProvider的初始化流程如下图:


ChangeNotifierProvider的初始化流程.png

那么,Provider是如何通过_InheritedProviderScopeElement实现添加监听和刷新的呢?

Provider的刷新机制-添加监听

我们在使用Provider时,通常将一个继承自ChangeNotifier的类(XXXProvider)的实例通过create参数传递给ChangeNotifierProvider,实际上,Provider内部会调用XXXProvider实例的addListener()方法来实现监听,所以需要找到XXXProvider实例的addListener()方法实在什么位置被调用的。

create实例的传递

还是需要看ChangeNotifierProvider的源码:

typedef Create<T> = T Function(BuildContext context);
 
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,
        );
 
  ...
 
  static void _dispose(BuildContext context, ChangeNotifier? notifier) {
    notifier?.dispose();
  }
}
  • 这里的Create是一个Function,返回了一个继承自ChangeNotifier的实例;
  • 新增了_dispose()方法,传给了父类(ListenableProvider);

ListenableProvider的源码:

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,
        );
 
  ...
 
  static VoidCallback _startListening(InheritedContext e, Listenable? value,) {
    value?.addListener(e.markNeedsNotifyDependents);
    return () => value?.removeListener(e.markNeedsNotifyDependents);
  }
}
  • 此处将create和_startListening()方法传递给了父类(InheritedProvider);

InheritedProvider的源码:

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);
 
  ...
}
  • 此处将子类传递归来的create实例、_dispose()方法、_startListening()方法传递给了_CreateInheritedProvider;

create实例传递的流程如下图:


create实例传递的流程.png

_CreateInheritedProvider

_CreateInheritedProvider的源码:

@immutable
abstract class _Delegate<T> {
  _DelegateState<T, _Delegate<T>> createState();
 
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
}
 
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();
}
  • _CreateInheritedProvider继承自抽象类_Delegate,实现了其createState()方法;
  • createState()方法返回了一个_CreateInheritedProviderState实例,照理说,主要逻辑都应该在_CreateInheritedProviderState里;
  • 这里的createState()方法与StatefulWidget中的createState()方法不同,_CreateInheritedProvider在初始化时不会主动调用createState()方法,所以在看_CreateInheritedProviderState的源码之前,我们先找到_CreateInheritedProvider中的createState()方法实在何处被调用的;
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);
 
  ...
 
  final _Delegate<T> _delegate;
  final bool? _lazy;
  final TransitionBuilder? builder;
 
  ...
 
  @override
  Widget buildWithChild(BuildContext context, Widget? child) {
    ...
    return _InheritedProviderScope<T>(
      owner: this,
      debugType: kDebugMode ? '$runtimeType' : '',
      child: builder != null
          ? Builder(
              builder: (context) => builder!(context, child),
            )
          : child!,
    );
  }
}
  • InheritedProvider实例的_delegate参数被赋值为一个_CreateInheritedProvider实例;
  • buildWithChild()方法返回的_InheritedProviderScope实例有一个owner参数,参数值为InheritedProvider实例本身;
class _InheritedProviderScope<T> extends InheritedWidget {
  const _InheritedProviderScope({
    required this.owner,
    required this.debugType,
    required Widget child,
  }) : 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);
  }
}
  • createElement()方法返回了一个_InheritedProviderScopeElement实例,关键部分在_InheritedProviderScopeElement中;

_InheritedProviderScopeElement的源码(精简后):


class _InheritedProviderScopeElement<T> extends InheritedElement
    implements InheritedContext<T> {
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
      : super(widget);
 
  ...
 
  @override
  void performRebuild() {
    if (_firstBuild) {
      _firstBuild = false;
      _delegateState = widget.owner._delegate.createState()..element = this;
    }
    super.performRebuild();
  }
 
  ...
}
  • 关键代码找到了!widget.owner._delegate.createState()..element = this
  • widget(_InheritedProviderScope)→ owner(InheritedProvider)→ _delegate(_CreateInheritedProvider);
  • 可以看到,在_InheritedProviderScopeElement初始化(框架入口ChangeNotifierProvider初始化)时,经过一些列的回溯与调用,_CreateInheritedProviderState就已经被初始化了;
  • 除了_CreateInheritedProviderState实例的初始化外,还将_InheritedProviderScopeElement实例本身赋值给_CreateInheritedProviderState实例的element属性,这个后面会讲到;

_CreateInheritedProvider的createState()方法调用流程如下:


_CreateInheritedProvider的createState()方法调用流程.png

根据以上流程我们可知,_CreateInheritedProvider中的createState()方法是在ChangeNotifierProvider初始化时就被调用的,因此我们可以接着去看_CreateInheritedProviderState的源码;

_CreateInheritedProviderState

_CreateInheritedProviderState的源码(精简后):

class _CreateInheritedProviderState<T> extends _DelegateState<T, _CreateInheritedProvider<T>> {
  VoidCallback? _removeListener;
  bool _didInitValue = false;
  T? _value;
  _CreateInheritedProvider<T>? _previousWidget;
 
  @override
  T get value {
    ...
 
    if (!_didInitValue) {
      _didInitValue = true;
      if (delegate.create != null) {
        assert(debugSetInheritedLock(true));
        try {
          ...
          _value = delegate.create!(element!);
        } finally {
          ...
        }
        ...
      }
      ...
    }
 
    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);
    }
  }
 
  ...
}
  • _CreateInheritedProviderState继承自_DelegateState;
  • 在ChangeNotifierProvider的初始化流程中的_dispose()、_startListening()、create实例都在_CreateInheritedProviderState中被使用;
  • 但以上的使用都要通过delegate,这个delegate是什么?盲猜是从父类(_DelegateState)继承而来的,我们去看下_DelegateState的源码;
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}) {}
}

果然,在_DelegateState中存在delegate属性

  • 关键代码:element!.widget.owner._delegate
  • element(_InheritedProviderScopeElement实例)→ widget(_InheritedProviderScope实例)→ owner(InheritedProvider)→ _delegate(_CreateInheritedProvider)
  • 由以上可知,_CreateInheritedProviderState中用来使用_dispose()、_startListening()、create实例等的delegate,就是ChangeNotifierProvider初始化时,在InheritedProvider中初始化的_delegate(_CreateInheritedProvider实例);
  • 根据上面提到的,_InheritedProviderScopeElement中有一行关键代码:widget.owner._delegate.createState()..element = this 可知,delegate的element属性在_InheritedProviderScopeElement时就被赋值了,所以一定不为空;

_DelegateState.element的初始化流程如下:


_DelegateState.element的初始化流程.png
class _CreateInheritedProviderState<T> extends _DelegateState<T, _CreateInheritedProvider<T>> {
  VoidCallback? _removeListener;
  bool _didInitValue = false;
  T? _value;
  _CreateInheritedProvider<T>? _previousWidget;
 
  @override
  T get value {
    ...
 
    if (!_didInitValue) {
      _didInitValue = true;
      if (delegate.create != null) {
        assert(debugSetInheritedLock(true));
        try {
          ...
          _value = delegate.create!(element!);
        } finally {
          ...
        }
        ...
      }
      ...
    }
 
    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);
    }
  }
 
  ...
}

其中有两个关键流程:
1)get 流程:

  • 我们传入的create会赋值给value属性,也就是说,现在的value属性就是我们一开始传入的XXXProvider实例;
  • 下面调用了startListening()方法,参数为element和value;
  • element即_InheritedProviderScopeElement实例,_InheritedProviderScopeElement继承自InheritedContext,相当于上下文实例;
  • value即XXXProvider实例;

2)dispose 流程

  • _CreateInheritedProviderState中定义了一个Callback → _removeListener,在调用startListening()方法时,_removeListener接收startListening()方法的返回值,并在dispose()方法中调用;
  • startListening()是在ListenableProvider初始化时被定义,根据前文贴出的ListenableProvider源码可知,startListening()方法的返回值是一个移除监听的操作(value?.removeListener());
  • 同时dispose()方法还调用了ChangeNotifierProvider初始化流程中定义的_dispose()方法(移除XXXProvider实例),至此,监听的回收流程也完成了;

最后还有一个问题,那就是_CreateInheritedProviderState中value的get方法是什么时候内调用的,其实在_InheritedProviderScopeElement的源码中有这样一段:

class _InheritedProviderScopeElement<T> extends InheritedElement
    implements InheritedContext<T> {
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
      : super(widget);
 
  late _DelegateState<T, _Delegate<T>> _delegateState;
 
  ...
 
  @override
  void performRebuild() {
    if (_firstBuild) {
      _firstBuild = false;
      _delegateState = widget.owner._delegate.createState()..element = this;
    }
    super.performRebuild();
  }
 
  @override
  void reassemble() {
    super.reassemble();
 
    final value = _delegateState.hasValue ? _delegateState.value : null;
    if (value is ReassembleHandler) {
      value.reassemble();
    }
  }
 
  ...
}
  • 在reassemble()方法中,调用了_delegateState.value;
  • reassemble()方法是Element的生命周期方法,在全局状态初始化后调用,即performRebuild()方法被调用后,Element的生命周期会调用reassemble()方法;
  • reassemble()方法中的_delegateState在performRebuild()方法中被初始化(_delegateState = widget.owner._delegate.createState()..element = this;);

总结

根据以上的梳理,可以总结下Provider的初始化以及调用流程,如下:


Provider的初始化以及调用流程.png

Provider的刷新机制-刷新逻辑

刷新触发与刷新流程

由以上分析可知,刷新触发的代码在ListenableProvider中,当XXXProvider实例收到通知消息(外部调用notifyListeners()方法)时,会触发value?.addListener(e.markNeedsNotifyDependents)方法;

ListenableProvider的源码:

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,
        );
 
  ...
 
  static VoidCallback _startListening(InheritedContext e, Listenable? value,) {
    value?.addListener(e.markNeedsNotifyDependents);
    return () => value?.removeListener(e.markNeedsNotifyDependents);
  }
}

因此刷新的关键逻辑就在e.markNeedsNotifyDependents的实现中,markNeedsNotifyDependents是通过InheritedContext这个上下文类来调用的;

而在Provider中,使用了_InheritedProviderScopeElement作为InheritedContext的实现类,因此我们需要看下_InheritedProviderScopeElement的源码:

class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
      : super(widget);
 
  ...
 
  @override
  void markNeedsNotifyDependents() {
    if (!_isNotifyDependentsEnabled) {
      return;
    }
 
    markNeedsBuild();
    _shouldNotifyDependents = true;
  }
 
  ...
}
  • 这里省略了其他代码,只保留markNeedsNotifyDependents()方法有关的代码;
  • markNeedsNotifyDependents()中除了调用了markNeedsBuild()方法外就没有其他逻辑了,我们需要看下markNeedsBuild()方法的实现;

markNeedsBuild()是Element类中的方法(_InheritedProviderScopeElement → InheritedElement → ProxyElement → ComponentElement→ Element),我们看下markNeedsBuild()的实现:

abstract class Element extends DiagnosticableTree implements BuildContext {
  ...
 
  /// Marks the element as dirty and adds it to the global list of widgets to
  /// rebuild in the next frame.
  ///
  /// Since it is inefficient to build an element twice in one frame,
  /// applications and widgets should be structured so as to only mark
  /// widgets dirty during event handlers before the frame begins, not during
  /// the build itself.
  void markNeedsBuild() {
    assert(_lifecycleState != _ElementLifecycle.defunct);
    if (_lifecycleState != _ElementLifecycle.active)
      return;
    assert(owner != null);
    assert(_lifecycleState == _ElementLifecycle.active);
    assert(() {
      if (owner!._debugBuilding) {
        assert(owner!._debugCurrentBuildTarget != null);
        assert(owner!._debugStateLocked);
        if (_debugIsInScope(owner!._debugCurrentBuildTarget!))
          return true;
        if (!_debugAllowIgnoredCallsToMarkNeedsBuild) {
          final List<DiagnosticsNode> information = <DiagnosticsNode>[
            ErrorSummary('setState() or markNeedsBuild() called during build.'),
            ErrorDescription(
              'This ${widget.runtimeType} widget cannot be marked as needing to build because the framework '
              'is already in the process of building widgets.  A widget can be marked as '
              'needing to be built during the build phase only if one of its ancestors '
              'is currently building. This exception is allowed because the framework '
              'builds parent widgets before children, which means a dirty descendant '
              'will always be built. Otherwise, the framework might not visit this '
              'widget during this build phase.',
            ),
            describeElement(
              'The widget on which setState() or markNeedsBuild() was called was',
            ),
          ];
          if (owner!._debugCurrentBuildTarget != null)
            information.add(owner!._debugCurrentBuildTarget!.describeWidget('The widget which was currently being built when the offending call was made was'));
          throw FlutterError.fromParts(information);
        }
        assert(dirty); // can only get here if we're not in scope, but ignored calls are allowed, and our call would somehow be ignored (since we're already dirty)
      } else if (owner!._debugStateLocked) {
        assert(!_debugAllowIgnoredCallsToMarkNeedsBuild);
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('setState() or markNeedsBuild() called when widget tree was locked.'),
          ErrorDescription(
            'This ${widget.runtimeType} widget cannot be marked as needing to build '
            'because the framework is locked.',
          ),
          describeElement('The widget on which setState() or markNeedsBuild() was called was'),
        ]);
      }
      return true;
    }());
    if (dirty)
      return;
    _dirty = true;
    owner!.scheduleBuildFor(this);
  }
 
  /// Called by the [BuildOwner] when [BuildOwner.scheduleBuildFor] has been
  /// called to mark this element dirty, by [mount] when the element is first
  /// built, and by [update] when the widget has changed.
  @pragma('vm:prefer-inline')
  void rebuild() {
    assert(_lifecycleState != _ElementLifecycle.initial);
    if (_lifecycleState != _ElementLifecycle.active || !_dirty)
      return;
    assert(() {
      debugOnRebuildDirtyWidget?.call(this, _debugBuiltOnce);
      if (debugPrintRebuildDirtyWidgets) {
        if (!_debugBuiltOnce) {
          debugPrint('Building $this');
          _debugBuiltOnce = true;
        } else {
          debugPrint('Rebuilding $this');
        }
      }
      return true;
    }());
    assert(_lifecycleState == _ElementLifecycle.active);
    assert(owner!._debugStateLocked);
    Element? debugPreviousBuildTarget;
    assert(() {
      debugPreviousBuildTarget = owner!._debugCurrentBuildTarget;
      owner!._debugCurrentBuildTarget = this;
      return true;
    }());
    performRebuild();
    assert(() {
      assert(owner!._debugCurrentBuildTarget == this);
      owner!._debugCurrentBuildTarget = debugPreviousBuildTarget;
      return true;
    }());
    assert(!_dirty);
  }
 
  /// Called by rebuild() after the appropriate checks have been made.
  @protected
  void performRebuild();
}

这里花里胡哨的写了一大堆,由于markNeedsBuild()内部的调用流程过于抽象,因此这里不再做具体的源码分析,不过根据markNeedsBuild()的方法注释可知,markNeedsBuild()被调用后会将Element实例打上脏标记,并缓存在一个全局的列表中;

  • 关键代码在owner!.scheduleBuildFor(this)中,这里是将Element实例打上脏标记,并缓存在全局的列表中的具体实现;
  • 另一个关键方法rebuild(),我们根据方法注释可知,该方法会在owner!.scheduleBuildFor()方法被调用后执行(由于调用过程过于抽象,在这不做具体分析了,感兴趣的小伙伴可以研究下);
  • 最终,我们发现在rebuild()方法的内部调用了performRebuild()方法;

调用流程:Element.performRebuild() → ComponentElement.performRebuild() → ComponentElement.build() → _InheritedProviderScopeElement.build();

总结一下Provider的刷新流程:

  1. 当外部调用notifyListeners()方法时,会触发XXXProvider实例的addListener()方法,进而调用InheritedContext类中的markNeedsNotifyDependents()方法;
  2. markNeedsNotifyDependents()方法内部会经过一些列的调用逻辑,最终调用其自身的performRebuild()方法;
  3. InheritedContext类中performRebuild()方法的实现在其子类ComponentElement类中;
  4. ComponentElement中的performRebuild()方法会调用其自身的build()方法,方法实现在其子类_InheritedProviderScopeElement类中;
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
      : super(widget);
 
  bool _shouldNotifyDependents = false;
  ...
 
    @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();
  }
 
  ...
}
  • 由于上面的markNeedsNotifyDependents()方法中已经给_shouldNotifyDependents设置为true,所以build内部逻辑会执行notifyClients;
  • notifyClients()方法的实现在其父类(InheritedElement)中;

由于InheritedElement中notifyClients()方法的具体实现涉及到太多层级的调用、Bind类、绘制流程等,因此这里不再贴源码进行分析,其内部实现的大体逻辑如下:

  1. 遍历全局HashMap – _dependents的所有key,取到对应的Element(_dependents的Key为Element类型);
  2. 每获取到一个Element实例,都会调用Element内部的didChangeDependencies()方法;
  3. didChangeDependencies()方法内部将当前Element打上一个标记,并调用与当前Element实例对应的widget实例的build方法;
  4. 而被打上标记的Element所对应的widget,我们根据以上流程也能看出来,就是前文所提到的Consumer;


    刷新流程.png

BuildContext

在上述的Provider源码分析中,我们发现其逻辑会大量的涉及到BuildContext类以及其相关类中的内容,那么这里我们来简单看一下BuildContext类究竟是什么。

BuildContext的源码:

abstract class BuildContext {
  Widget get widget;
 
  BuildOwner? get owner;
 
  bool get debugDoingBuild;
 
  RenderObject? findRenderObject();
 
  Size? get size;
 
  InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });
 
  T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });
 
  InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>();
 
  T? findAncestorWidgetOfExactType<T extends Widget>();
 
  T? findAncestorStateOfType<T extends State>();
 
  T? findRootAncestorStateOfType<T extends State>();
 
  T? findAncestorRenderObjectOfType<T extends RenderObject>();
 
  void visitAncestorElements(bool Function(Element element) visitor);
 
  void visitChildElements(ElementVisitor visitor);
 
  DiagnosticsNode describeElement(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty});
 
  DiagnosticsNode describeWidget(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty});
 
  List<DiagnosticsNode> describeMissingAncestor({ required Type expectedAncestorType });
 
  DiagnosticsNode describeOwnershipChain(String name);
}

我们可以看到,BuildContext是一个抽象类,约定了相关的功能,在不同的实现类中,相关方法的实现可能会有出入,但是不应偏离抽象方法注释所描述的功能范围;

最常见的BuildContext的实现类就是StatelessWidget(StatefulWidget的实现同理),我们来看下StatelessWidget类的源码:

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);
 
  @override
  StatelessWidget get widget => super.widget as StatelessWidget;
 
  @override
  Widget build() => widget.build(this);
 
  @override
  void update(StatelessWidget newWidget) {
    super.update(newWidget);
    assert(widget == newWidget);
    _dirty = true;
    rebuild();
  }
}
  • StatelessWidget抽象了build()方法,入参为BuildContext;
  • createElement()方法中实例化了StatelessElement类,并将自身(StatelessWidget实例)传入;
  • StatelessElement类中实现了ComponentElement类的build()方法,并在内部调用widget(传入的StatelessWidget实例)的build()方法;
abstract class ComponentElement extends Element {
  ...
 
  @protected
  Widget build();
 
  ...
}
 
abstract class Element extends DiagnosticableTree implements BuildContext {
     ...
}
  • ComponentElement继承Element,它抽象了一个build方法,StatelessElement实现了这个方法;
  • Element继承自实现了BuildContext的DiagnosticableTree类;
  • 可以这样理解:每个Widget都有对应的Element( 通过createElement()生成 ),Element是BuildContext实现类
@immutable
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
 
  final Key? key;
 
  @protected
  @factory
  Element createElement();
 
  ...
}

由于Widget类中抽象了createElement()方法,相当于每一个Widget的子类都有与其自身相对应的Element();

![image.png](https://upload-images.jianshu.io/upload_images/27941250-1c97cec4e1b63814.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

####Provider.of<T>()
为了将上面的流程串联起来,Provider使用了Provider.of()方法将刷新组件添加到InheritedElement中的_dependents变量里;

static T of<T>(BuildContext context, {bool listen = true}) {
    ...
 
    final inheritedElement = _inheritedElementOf<T>(context);
 
    if (listen) {
        context.dependOnInheritedElement(inheritedElement);
    }
    return inheritedElement.value;
}
 
 
static _InheritedProviderScopeElement<T> _inheritedElementOf<T>(BuildContext context) {
    ...
 
    _InheritedProviderScopeElement<T>? inheritedElement;
 
    if (context.widget is _InheritedProviderScope<T>) {
        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!;
}
  • of()方法中,会通过_inheritedElementOf<T>()方法获取到父组件节点中距离最近的继承自InheritedElement的XXXElement实例;
  • 在_inheritedElementOf<T>()方法内部,是通过 context.getElementForInheritedWidgetOfExactType()来实现的,继承自InheritedElement的Widget的子节点,可以通过该方法找到父组件节点中距离最近的继承自InheritedElement的XXXElement实例;
  • 拿到XXXElement实例之后,通过调用context.dependOnInheritedElement()方法,为当前的widget添加依赖;
abstract class Element extends DiagnosticableTree implements BuildContext {
  ...
 
  @override
  InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
    assert(ancestor != null);
    _dependencies ??= HashSet<InheritedElement>();
    _dependencies!.add(ancestor);
    ancestor.updateDependencies(this, aspect);
    return ancestor.widget;
  }
 
  ...
}
  • 这里面调用了ancestor.updateDependencies()方法,传入了当前widget对应的Element本身,以及继承自InheritedElement的XXXElement实例;

ancestor.updateDependencies()方法的实现:

class InheritedElement extends ProxyElement {
  ...
 
  @protected
  void setDependencies(Element dependent, Object? value) {
    _dependents[dependent] = value;
  }
 
  @protected
  void updateDependencies(Element dependent, Object? aspect) {
    setDependencies(dependent, null);
  }
 
  ...
}
  • 方法内部调用了setDependencies方法;
  • setDependencies方法,将子Widget的Element实例赋值给了继承InheritedElement的类的 _dependents 变量;
image.png

自定义Builder

通过上面的分析,我们已经了解了provider的刷新机制,我们可以自定义一个Build来代替provider中Consumer的作用;

builder代码如下:

class NewBuilder<T> extends StatelessWidget {
  const NewBuilder(
    this.builder, {
    Key? key,
  }) : super(key: key);
 
  final Widget Function() builder;
 
  @override
  Widget build(BuildContext context) {
    Provider.of<T>(context);
    return builder();
  }
}

provider层:

class CustomBuilderProvider extends ChangeNotifier {
  int count = 0;
 
  void increment() {
    count++;
    notifyListeners();
  }
}

view层:

class CustomBuilderPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (BuildContext context) => CustomBuilderProvider(),
      builder: (context, child) => _buildPage(context),
    );
  }
 
  Widget _buildPage(BuildContext context) {
    final provider = context.read<CustomBuilderProvider>();
 
    return Scaffold(
      appBar: AppBar(title: Text('Provider-自定义Builder范例')),
      body: Center(
        child: NewBuilder<CustomBuilderProvider>(
          () => Text(
            '点击了 ${provider.count} 次',
            style: TextStyle(fontSize: 30.0),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => provider.increment(),
        child: Icon(Icons.add),
      ),
    );
  }
}

以上便完成了通过自定义builder实现一个简单的点击按钮自动刷新页面文字内容的功能了。

MultiProvider

一般情况下,我们在main主入口写全局Provider的时候,会使用MultiProvider,如下:

void main() {
  runApp(MyApp());
}
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(builder: (BuildContext context, Widget? child) {
      return MultiProvider(child: child, providers: [
        //此处通过MultiProvider创建的Provider是全局的
        ChangeNotifierProvider.value(value: ProSpanOneProvider()),
      ]);
    });
  }
}

那么MultiProvider都做了什么呢?我们来看下MultiProvider的源码:

class MultiProvider extends Nested {
  MultiProvider({
    Key? key,
    required List<SingleChildWidget> providers,
    Widget? child,
    TransitionBuilder? builder,
  }) : super(
          key: key,
          children: providers,
          child: builder != null
              ? Builder(
                  builder: (context) => builder(context, child),
                )
              : child,
        );
}
  • MultiProvider继承自Nested类,Nested可以优化一些布局嵌套问题,感兴趣的可查看Nested Pub
  • 可以看到,MultiProvider将Provider实例套在了顶层的widget上;

Consumer

Consumer是使用provider过程中最常用的一个控件,我们来看看Consumer的源码:

class Consumer<T> extends SingleChildStatelessWidget {
  Consumer({
    Key? key,
    required this.builder,
    Widget? child,
  }) : super(key: key, child: child);
 
  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内部重写了buildWithChild()方法,内部调用了Provider.of<T>()方法;
  • 所以Consumer的本质就是一个可以获取最近父控件的InIneritedElement实例,并与自身绑定依赖(可获取刷新能力)的widget;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容