Flutter的Provider是专门为Flutter处理状态而生,RenderObject树的重新渲染最原始的做法就是调用SetState方法,而Provider可以让你注重于数据逻辑的的改变,而无需关心RenderObject树的主动渲染,这不就是类似于mvvm模式,只要数据变化了,view树就会重新渲染该渲染的部分,而不需要咱们主动调用渲染。
下边先来看看Provider相关类怎么用,这里以官方demo为例
runApp(
// Provide the model to all widgets within the app. We're using
// ChangeNotifierProvider because that's a simple way to rebuild
// widgets when a model changes. We could also just use
// Provider, but then we would have to listen to Counter ourselves.
//
// Read Provider's docs to learn about all the available providers.
ChangeNotifierProvider(
// Initialize the model in the builder. That way, Provider
// can own Counter's lifecycle, making sure to call `dispose`
// when not needed anymore.
create: (context) => Counter(),
child: MyApp(),
),
);
}
class Counter with ChangeNotifier {
int value = 0;
void increment() {
value += 1;
notifyListeners();
}
}
return Scaffold(
appBar: AppBar(
title: Text('Flutter Demo Home Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//使用数据
Consumer(
builder: (context, counter, child) => Text(
'${counter.value}',
style: Theme.of(context).textTheme.display1,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
//操作数据
onPressed: () =>
Provider.of(context, listen: false).increment(),
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
这个demo的使用无非就四点,用ChangeNotifierProvider套在显示的的Widget的上层,创建实现ChangeNotifier 的类,需要显示数据的小部件套上一层Consumer,逻辑处理和重新渲染View树用Provider.of
先来看一下ChangeNotifierProvider的实现
class ChangeNotifierProvider
extends ListenableProvider
ChangeNotifierProvider继承自ListenableProvider,它的build方法最终返回
Widget build(BuildContext context) {
final delegate = this.delegate as _ListenableDelegateMixin;
return InheritedProvider(
value: delegate.value,
updateShouldNotify: delegate.updateShouldNotify,
child: child,
);
InheritedProvider,InheritedProvider又继承自InheritedWidget,所以ChangeNotifierProvider一个作用就是让所有的子部件可以共享create方法返回的对象,也就是本例子中的Counter类
class InheritedProvider extends InheritedWidget
ChangeNotifierProvider的父类ListenableProvider在创建的时候,会构建一个_BuilderListenableDelegate,而ChangeNotifierProvider在创建Element树时会构建_DelegateElement,有关渲染树的创建(widget、element、RenderObject的关系)请参考flutter的UI树渲染流程,_DelegateElement在创建之前会先执行_DelegateWidgetState的initState方法
void initState() {
super.initState();
_mountDelegate();
_initDelegate();
}
void _initDelegate() {
assert(() {
(context as _DelegateElement)._debugIsInitDelegate = true;
return true;
}());
//这里的delegate是_BuilderListenableDelegate
widget.delegate.initDelegate();
assert(() {
(context as _DelegateElement)._debugIsInitDelegate = false;
return true;
}());
}
最终会调用回_BuilderListenableDelegate的initDelegate方法
void initDelegate() {
super.initDelegate();
if (value != null) startListening(value);
}
void startListening(T listenable, {bool rebuild = false}) {
final setState = this.setState;
//声明观察方法
final listener = () => setState(() => buildCount++);
......
//注册观察者
listenable.addListener(listener);
....
}
而最终被调用的startListening方法主要用来向ChangeNotifier 的实现类中添加监听,一旦ChangeNotifier 数据变化了,那么ChangeNotifierProvider的setState 方法会被调用从而引起树的重新渲染,也就是说ChangeNotifierProvider是观察者,而ChangeNotifier 实现类是被观察者。
好了,继续看ChangeNotifier 这个被观察者的实现
class ChangeNotifier implements Listenable {
ObserverList _listeners = ObserverList();
@protected
bool get hasListeners {
assert(_debugAssertNotDisposed());
return _listeners.isNotEmpty;
}
//添加观察者
@override
void addListener(VoidCallback listener) {
assert(_debugAssertNotDisposed());
_listeners.add(listener);
}
//通知观察者改变了数据,view树重新变化
@protected
@visibleForTesting
void notifyListeners() {
assert(_debugAssertNotDisposed());
if (_listeners != null) {
final List localListeners = List.from(_listeners);
for (VoidCallback listener in localListeners) {
try {
if (_listeners.contains(listener))
listener();
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'foundation library',
context: ErrorDescription('while dispatching notifications for $runtimeType'),
informationCollector: () sync* {
yield DiagnosticsProperty(
'The $runtimeType sending notification was',
this,
style: DiagnosticsTreeStyle.errorProperty,
);
},
));
}
}
}
}
}
这个类主要就是实现了观察者回调的方法集合ObserverList
addListener用来添加观察者,notifyListeners用来通知观察者。
Consumer的就是将被观察者ChangeNotifier 的真正实现类实现的获得并交个builder方法传给子Widget用来操作数据的
Widget build(BuildContext context) {
return builder(
context,
Provider.of(context),
child,
);
Provider.of(context, listen: false) 方法就是获得被观察者来处理数据逻辑然后通知观察者重新渲染的
static T of(BuildContext context, {bool listen = true}) {
// this is required to get generic Type
final type = _typeOf>();
final provider = listen
? context.inheritFromWidgetOfExactType(type) as InheritedProvider
: context.ancestorInheritedElementForWidgetOfExactType(type)?.widget
as InheritedProvider;
if (provider == null) {
throw ProviderNotFoundError(T, context.widget.runtimeType);
}
return provider._value;
}
因为ChangeNotifierProvider最终返回的子Widget是InheritedWidget所以Provider.of方法利用了InheritedWidget包裹的所有子widget共享数据的特性可以拿到被观察者对象实现业务逻辑从而更改ui渲染,其实ChangeNotifier 作用可以看做viewModel,当然你可以继续扩展。
说到底Provider的状态实现其实就是观察者模式,观察者是ui,被观察者是model用来处理数据并调用notifyListeners通知ui的更新,等待垂直信号的到来渲染。
当然Provider的使用还有MultiProvider、Provider、ChangeNotifierProxyProvider的实现类供我们使用,原理是一样的,无非MultiProvider可以包裹多个观察者和被观察者。