Provider是Flutter中的一个状态管理框架,也算是入侵性非常小的一个状态管理库。这里说的入侵性小,指的是它并没有引入什么新的概念,完全就是基于Flutter内部一些功能所做的封装。
数据传递 状态管理的一个基础就是数据共享,而数据共享指的是多个子组件间可以共享状态,也就是进行状态提升。Provider用于提供状态的方式有很多,主要用于提供不同的状态类型,他们都是以Provider结尾的类。
例如下面通过Provider提供一个数据:
1 2 3 4 Provider<CircleController>( create: (context) => CircleController(), child: MyChildWidget(), )
例如上述代码,通过Provider提供一个CircleController对象,这样在它的子组件MyChildWidget,以及更深层级的子组件中都能够获取到CircleController,从而使用它内部的状态,或者说它本身也可以是一个状态。
实际上我们是知道在Flutter中,想向子组件传递数据,要么通过构造方法层层传入,要么构建一个独立于组件的对象来进行共享,要么就是通过InheritedWidget进行传递,Provider使用的就是最后一种方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Provider <T > extends InheritedProvider <T > { Provider({ Key? key, required Create<T> create, Dispose<T>? dispose, bool? lazy, TransitionBuilder? builder, Widget? child, }) : super ( key: key, lazy: lazy, builder: builder, create: create, dispose: dispose, debugCheckInvalidValueType: kReleaseMode ? null : (T value) => Provider.debugCheckInvalidValueType?.call<T>(value), child: child, ); ... }
在剔除掉一些静态方法后,可以看到Provider类实际上就是对InheritedProvider的一个包装,基本上没有做什么操作,再继续跟踪InheritedProvider:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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 _InheritedProviderElement<T> createElement() { return _InheritedProviderElement<T>(this ); } @override Widget buildWithChild(BuildContext context, Widget? child) => _buildWithChild(child); Widget _buildWithChild(Widget? child, {Key? key}) { return _InheritedProviderScope<T?>( owner: this , key: key, debugType: kDebugMode ? '$runtimeType ' : '' , child: builder != null ? Builder( builder: (context) => builder!(context, child), ) : child!, ); } }
InheritedProvider在构造方法中提供了一系列的参数,参数实际上是在不同类型的Provider中使用的,这里先不去关注,因为它将这些参数统一打包在了一个代理对象中_CreateInheritedProvider,后续如果需要使用,就直接从代理对象中获取。
然后就是buildWithChild方法,这是构建布局的一个方法,在InheritedProvider中可以看到,它实际上调用的是构造方法传入的builder来完成布局的,并且在这个布局外面又套了一层_InheritedProviderScope。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class _InheritedProviderScope <T > extends InheritedWidget { _InheritedProviderScope({ required this .owner, required this .debugType, required Widget child, Key? key, }) : assert (null is T), super ( key: key, 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的,并且它持有了外部的InheritedProvider,也就是间接拿到了构造方法中传入的各种参数。注意在updateShouldNotify时,直接返回false。因此,但状态发生变化时,它是不会通知依赖的子组件进行更新的。
再回到最初的示例:
1 2 3 4 Provider<CircleController>( create: (context) => CircleController(), child: MyChildWidget(), )
此时组件树是如下所示的:
1 Provider -> _InheritedProviderScope -> MyChildWidget
其中_InheritedProviderScope是InheritedWidget类型,因此它的子组件就能通过context获取到_InheritedProviderScope,从而可以拿到它提供的状态。
继承关系如下:
对于普通的Provider提供状态,我们看到了实际上就是包了一层InheritedWidget来提供状态,并且它提供的状态变化时,还不会通知到子组件进行重建,因此我们使用它来提供状态是非常有限的,我们常用的是ChangeNotifier,而它是继承自ListenableProvider。那把上面的例子替换成ListenableProvider:
1 2 3 4 ListenableProvider<CircleController>( create: (context) => CircleController(), child: MyChildWidget(), )
用法上和Provider是一致的,包括参数列表也是一样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 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<Listenable?> e, Listenable? value, ) { value?.addListener(e.markNeedsNotifyDependents); return () => value?.removeListener(e.markNeedsNotifyDependents); } }
ListenableProvider也是继承自InheritedProvider,它比Provider多的一点就是它额外传递了一个startListening参数,该参数的内部逻辑是向Listenable参数添加监听,并返回一个移除监听的回调,当监听到内容变化后,会通知依赖的子组件进行刷新。
还有ChangeNotifierProvider:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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(); } }
经过上述三个Provider的分析,我们看到他们实际上都是对InheritedProvider的包装,主要的区别就是传入的参数不同。其中Provider只传入了必要的参数,ListenableProvider额外提供了startLintening参数,而ChangeNotifierProvider又多了一个_dispose参数。并且值得注意的是,这些参数并没有直接使用,而是包装在了_delegate中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 abstract class _Delegate <T > { _DelegateState<T, _Delegate<T>> createState(); void debugFillProperties(DiagnosticPropertiesBuilder properties) {} }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}) {} }
代理对象_delegate实际是一个_Dalegate类型,它内部有个方法用于创建_DelegateState,这个State类主要作用就是存储需要提供的数据以及响应组件的生命周期,在InheritedProvider中它的实现类是_CreateInheritedProvider:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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(); }
然后是_DelegateState的实现类,这里对应的是_CreateInheritedProviderState:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 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 && _initError != null ) { ... } ... if (!_didInitValue) { _didInitValue = true ; if (delegate.create != null ) { _value = delegate.create!(element!); } if (delegate.update != null ) { _value = delegate.update!(element!, _value); } } _removeListener ??= delegate.startListening?.call(element!, _value as T); return _value as T; } @override void dispose() { super .dispose(); _removeListener?.call(); if (_didInitValue) { delegate.dispose?.call(element!, _value as T); } } @override void build({required bool isBuildFromExternalSources}) { var shouldNotify = false ; if (isBuildFromExternalSources && _didInitValue && delegate.update != null ) { final previousValue = _value; _value = delegate.update!(element!, _value as T); if (delegate._updateShouldNotify != null ) { shouldNotify = delegate._updateShouldNotify!( previousValue as T, _value as T, ); } else { shouldNotify = _value != previousValue; } if (shouldNotify) { if (_removeListener != null ) { _removeListener!(); _removeListener = null ; } _previousWidget?.dispose?.call(element!, previousValue as T); } } if (shouldNotify) { element!._shouldNotifyDependents = true ; } _previousWidget = delegate; return super .build(isBuildFromExternalSources: isBuildFromExternalSources); } @override bool get hasValue => _didInitValue; }
_DelegateState控制了整个组件的状态逻辑,首先就是在获取值时,使用的是懒加载模式,也就是只有第一次获取值的时候才会触发ceate来创建值,并且创建完之后会立即触发一次update,然后建立监听。然后就是在dispose的时候移除监听并且触发参数传入的Dispose。最后是build方法,也就是界面构建的时候会再次触发update,并且触发updateShouldNotify来决定是否需要通知子组件刷新,如果依赖子组件需要刷新,就会先移除掉监听并且dispose掉。
也就是说几乎所有的逻辑都发生在_CreateInheritedProviderState中,而_CreateInheritedProviderState又是发生在_InheritedProviderScopeElement中进行关联的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class _InheritedProviderScope <T > extends InheritedWidget { ... @override _InheritedProviderScopeElement<T> createElement() { return _InheritedProviderScopeElement<T>(this ); } }class _InheritedProviderScopeElement <T > extends InheritedElement implements InheritedContext <T > { late final _DelegateState<T, _Delegate<T>> _delegateState = widget.owner._delegate.createState()..element = this ; @override void update(_InheritedProviderScope<T> newWidget) { _updatedShouldNotify = _delegateState.willUpdateDelegate(newWidget.owner._delegate); super .update(newWidget); _updatedShouldNotify = false ; } @override Widget build() { if (widget.owner._lazy == false ) { value; } _delegateState.build( isBuildFromExternalSources: _isBuildFromExternalSources, ); return super .build(); } @override void unmount() { _delegateState.dispose(); super .unmount(); } @override bool get hasValue => _delegateState.hasValue; @override T get value => _delegateState.value; }
到这里基本上所有的逻辑都看完了,_delegateState是_InheritedProviderScopeElement触发的,如果指定懒加载为false,则会在build前通过访问代理类中的值来触发加载数据;否则只有在第一次访问值时才会触发create来创建数据。
时序图如下:
主要逻辑发生在_InheritedProviderScopeElement中,然后触发_CreateInheritedProviderState进行更新。
首先就是获取依赖值value,只有获取值的时候才会调用create来创建值,即实现的懒加载场景,并且同时触发一次update。其次就是获取值的时候,如果没有加入监听,则会startListening来监听值的变化,当值变化时候回调函数会通知依赖的子组件刷新。 _InheritedProviderScopeElement#build的时候,如果是非懒加载情况,会直接访问一次value来触发创建依赖值。然后调用代理类的build,然后调用update一次,然后再根据_updateShouldNotify来决定是否通知依赖子组件进行更新,如果需要更新就移除监听removeListener并dispose。_InheritedProviderScopeElement#unmount的时候会触发dispose和removeListener。数据获取 数据获取方式有几种,基本上没啥太大的区别,主要就是是否需要进行依赖而已。
1 2 3 4 5 6 7 T watch<T>() { return Provider.of<T>(this ); } T read<T>() { return Provider.of<T>(this , listen: false ); }
状态的获取有read和watch两种方式,他们都是定义的BuildContext的拓展方法,实际走的逻辑还是Provider中的of静态方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 static T of<T>(BuildContext context, {bool listen = true }) { final inheritedElement = _inheritedElementOf<T>(context); if (listen) { context.dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>(); } final value = inheritedElement?.value; if (_isSoundMode) { if (value is ! T) { throw ProviderNullException(T, context.widget.runtimeType); } return value; } return value as T; }static _InheritedProviderScopeElement<T?>? _inheritedElementOf<T>( BuildContext context, ) { final inheritedElement = context.getElementForInheritedWidgetOfExactType< _InheritedProviderScope<T?>>() as _InheritedProviderScopeElement<T?>?; if (inheritedElement == null && null is ! T) { throw ProviderNotFoundException(T, context.widget.runtimeType); } return inheritedElement; }
获取方式也是我们非常熟悉的方式,注意当我们使用Provider时,实际上会在子布局外包裹一层_InheritedProviderScope,实际的数据以及回调方法都是由它来提供的,因此我们获取数据时也是通过这个类型来获取的。对于普通获取,直接通过get方法拿到数据,对于依赖方式获取,通过dependOn方式拿到数据,在通过依赖方式获取状态时,会去将context所指向的element添加到依赖列表中,这样当_InheritedProviderScope发生变化时就能通知到我们进行重建。
还有一个有区别的方法就是select,它能够选择性能依赖某几个字段,当固定的字段发生变化时,才会触发重建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 R select<T, R>(R Function (T value) selector) { final inheritedElement = Provider._inheritedElementOf<T>(this ); try { final value = inheritedElement?.value; final selected = selector(value); if (inheritedElement != null ) { dependOnInheritedElement( inheritedElement, aspect: (T? newValue) { return !const DeepCollectionEquality() .equals(selector(newValue), selected); }, ); } else { dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>(); } return selected; } finally { ... } }
select实际上是将变化的值进行筛选,或者说是做一下map的操作,将状态值转换成别的值并返回,后续也是当状态发生变化时,再进行转换,如果转换后的值不一致,则再去进行通知,从而可以避免其他状态值的影响。