Flutter——sdk:状态管理provider

Posted wzj_what_why_how

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter——sdk:状态管理provider相关的知识,希望对你有一定的参考价值。

provider

provider初识

  • 状态管理框架
  • Provider 用于提供数据, 它的目标就是完全替代 StatefulWidget。

不同类型的provider

  • Provider 最基础的 provider 组成,接收一个任意值并暴露它。
  • ListenableProvider 供可监听对象使用的特殊 provider。ListenableProvider 会监听对象,并在监听器被调用时更新依赖此对象的 widgets。
  • ChangeNotifierProvider 为 ChangeNotifier 提供的 ListenableProvider 规范,会在需要时自动调用 ChangeNotifier.dispose。【目前项目实践中用到这个比较多】
  • ValueListenableProvider 监听 ValueListenable,并且只暴露出 ValueListenable.value。
  • StreamProvider 监听流,并暴露出当前的最新值。
  • FutureProvider 接收一个 Future,并在其进入 complete 状态时更新依赖它的组件。

三个类

三个类分成了三个步骤:

  • ChangeNotifier:创建数据 Model。用于提供notifyListeners()方法,达到自动通知更新 UI。
  • ChangeNotifierProvider:创建顶层共享数据,持有 with ChangeNotifier 的model。
  • Consumer: 控制Widget的刷新颗粒度。

ChangeNotifier:

  • 用于向监听器发送通知。换言之,如果被定义为 ChangeNotifier,你可以订阅它的状态变化。(和观察者模式相类似)。

网上的一个例子说明:

///这里需要混入ChangeNotifier
class CounterModel with ChangeNotifier 
  int _count;///唯一字段_count(下划线代表私有)
  CounterModel(this._count);

  ///写一个增加的方法。然后需要调用notifyListeners();这个方法是通知用到Counter对象的widget刷新用的。
  void add() 
    _count++;
    notifyListeners();
  
  get count => _count;//get方法,将数据暴露出来

tip:唯一一行和 ChangeNotifier 相关的代码就是调用 notifyListeners()。当模型发生改变并且需要更新 UI 的时候可以调用该方法。而剩下的代码就是 CartModel 和它本身的业务逻辑。
ChangeNotifier 是 flutter:foundation 的一部分,而且不依赖 Flutter 中任何高级别类。


ChangeNotifierProvider

  • ChangeNotifierProvider widget 可以向其子孙节点暴露一个 ChangeNotifier。
  • ChangeNotifierProvider.value 不仅能够提供数据供子孙节点使用,还可以在数据改变的时候通知所有听众刷新。(通过之前我们说过的 notifyListeners)
  • ChangeNotifierProvider 放在什么位置:在需要访问它的 widget 之上。
void main() 
  runApp(ChangeNotifierProvider.value(
      value: CounterModel(),// 需要共享的数据资源
      child: MyApp()
  ));


Consumer

  • 问题: 使用 Provider.of 获取资源,可以得到资源暴露的数据的读写接口,在实现数据的共享和同步上还是比较简单的。
    但是,滥用 Provider.of 方法也有副作用,那就是当数据更新时,页面中其他的子 Widget 也会跟着一起刷新。
    那么,有没有办法能够在数据资源发生变化时,只刷新对资源存在依赖关系的 Widget,而其他 Widget 保持不变呢?
  • 解决:基于 Consumer, Provider 可以精确地控制 UI 刷新粒度。Consumer 使用了 Builder 模式创建 UI,收到更新通知就会通过 builder 重新构建 Widget。
body: Center(
  child: Consumer<CountModel>(
    builder: (context,CountModel counter,_) => Text('第二个页面count:$counter.counter'),
  ),

),
floatingActionButton: Consumer<CountModel>(
    builder: (context, CountModel counter, child) => FloatingActionButton(
        onPressed: counter.increment,
        child: child,
    ),
    child: MyIcon(),
)

Selector

Selector和Consumer是等价的,也是通过Provider.of获取数据的,不同的是,Selector正如他的名字一样,
他会过滤掉一些不必要的数据更新从而阻止重新构建,也就是说Selector只会更新符合条件的数据。

  • Selector<A, S>中的泛型:

    • A是我们从顶层获取的Provider的类型
    • S是我们关心的具体类型,也就是获取到的Provider中真正对我们有用的类型,需要在selector 中返回该类型。这个Selector的刷新范围也从整个Provider变成了 S。
  • Selector的中的属性:

    • selector:就是一个Function,入参会将我们获取的顶层 provider传入,然后再返回我们所关心的S。
    • shouldRebuild:这个属性会储存selector过滤后的值,也就是selector返回的S 并拿收到通知之后新的S与缓存的S进行比较,
      以此来判断这个Selector是否需要重新构建,默认preview!=next就刷新,如果是collection,selector进行深度比较。
    • builder:和Consumer一样,这里返回的是要构建的控件,第二个参数provider,就是我们刚才selector中返回的S。
    • child:这个用于优化一些不用刷新的部分,和Consumer一样。


实现原理

  • Provider是Flutter官方开发维护的,也是近些年官方最为推荐的状态管理库。其特点是:不复杂、好理解,可控度高。
  • Provider主要是对 InheritedWidget 组件进行上层封装,使其更易用,通过ChangeNotifier来处理数据,从而减少了InheritedWidget的大量模版代码。
  • 从源码上我们可以看到Provider直接继承于InheritedProvider,通过工厂构造函数Provider.value传入model和child节点,
    然后通过context.dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>();对值进行监听。
    而_InheritedProviderScope就是继承于InheritedWidget的。

优缺点

  • 【优点】使用简单。model继承ChangeNotifier,没有更多的布局widget,只需要通过context.read / context.watch操作或者监听model即可;
  • 【优点】颗粒度把控简单。为了解决widget重新build太频繁的问题,官方推出了context.select来监听对象的部分属性。也可使用Consumer/Selector进行布局;
  • 【优点】基于官方InheritedWidget的封装,不存在任何风险,很稳定且不会给性能方面加负担
  • 【缺点】context强关联,有Flutter开发经验的都知道,context大多时候基本都是在widget中才能获取到,
    在其他地方想随时获取 BuildContext 是不切实际的,也就意味着大多时候只能在view层去获取到Provider提供的信息。

注意事项

  • 注意provider组件位于父节点位置,这样子节点才能共享数据状态,
  • 其次我们尽可能的减少我们刷新的颗粒度,最好在使用数据的地方进行刷新组件。

以上是关于Flutter——sdk:状态管理provider的主要内容,如果未能解决你的问题,请参考以下文章

Flutter——sdk:状态管理provider

flutter Provide (状态管理篇)

Flutter Provider状态管理

flutter中的状态管理Provider

社区说|Flutter 主流状态管理框架 provider get 分析

从 Selector 访问多个字段(在 Flutter 中使用 Provider 状态管理时)?