flutter的Provider状态管理原理详解

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: <Widget>[
         //使用数据
            Consumer<Counter>(
              builder: (context, counter, child) => Text(
                '${counter.value}',
                style: Theme.of(context).textTheme.display1,
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        //操作数据
        onPressed: () =>
            Provider.of<Counter>(context, listen: false).increment(),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );

这个demo的使用无非就四点,用ChangeNotifierProvider套在显示的的Widget的上层,创建实现ChangeNotifier 的类,需要显示数据的小部件套上一层Consumer,逻辑处理和重新渲染View树用Provider.of<Counter>(context, listen: false)操作。

先来看一下ChangeNotifierProvider的实现

class ChangeNotifierProvider<T extends ChangeNotifier>
    extends ListenableProvider<T>

ChangeNotifierProvider继承自ListenableProvider,它的build方法最终返回

Widget build(BuildContext context) {
    final delegate = this.delegate as _ListenableDelegateMixin<T>;
    return InheritedProvider<T>(
      value: delegate.value,
      updateShouldNotify: delegate.updateShouldNotify,
      child: child,
    );

InheritedProvider,InheritedProvider又继承自InheritedWidget,所以ChangeNotifierProvider一个作用就是让所有的子部件可以共享create方法返回的对象,也就是本例子中的Counter

class InheritedProvider<T> 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;
    }());
  }
最终会调用回_BuilderListenableDelegateinitDelegate方法
 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 数据变化了,那么ChangeNotifierProvidersetState 方法会被调用从而引起树的重新渲染,也就是说ChangeNotifierProvider是观察者,而ChangeNotifier 实现类是被观察者。

好了,继续看ChangeNotifier 这个被观察者的实现

class ChangeNotifier implements Listenable {
  ObserverList<VoidCallback> _listeners = ObserverList<VoidCallback>();
  @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<VoidCallback> localListeners = List<VoidCallback>.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<ChangeNotifier>(
                'The $runtimeType sending notification was',
                this,
                style: DiagnosticsTreeStyle.errorProperty,
              );
            },
          ));
        }
      }
    }
  }
}

这个类主要就是实现了观察者回调的方法集合ObserverList<VoidCallback> _listeners = ObserverList<VoidCallback>(),

addListener用来添加观察者,notifyListeners用来通知观察者。

Consumer的就是将被观察者ChangeNotifier 的真正实现类实现的获得并交个builder方法传给子Widget用来操作数据的
 Widget build(BuildContext context) {
    return builder(
      context,
      Provider.of<T>(context),
      child,
    );
Provider.of<Counter>(context, listen: false)方法就是获得被观察者来处理数据逻辑然后通知观察者重新渲染的
static T of<T>(BuildContext context, {bool listen = true}) {
    // this is required to get generic Type
    final type = _typeOf<InheritedProvider<T>>();
    final provider = listen
        ? context.inheritFromWidgetOfExactType(type) as InheritedProvider<T>
        : context.ancestorInheritedElementForWidgetOfExactType(type)?.widget
            as InheritedProvider<T>;

    if (provider == null) {
      throw ProviderNotFoundError(T, context.widget.runtimeType);
    }

    return provider._value;
  }

因为ChangeNotifierProvider最终返回的子WidgetInheritedWidget所以Provider.of方法利用了InheritedWidget包裹的所有子widget共享数据的特性可以拿到被观察者对象实现业务逻辑从而更改ui渲染,其实ChangeNotifier 作用可以看做viewModel,当然你可以继续扩展。

说到底Provider的状态实现其实就是观察者模式,观察者是ui,被观察者是model用来处理数据并调用notifyListeners通知ui的更新,等待垂直信号的到来渲染。

当然Provider的使用还有MultiProvider、ProviderChangeNotifierProxyProvider的实现类供我们使用,原理是一样的,无非MultiProvider可以包裹多个观察者和被观察者。

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值