关于Flutter中的状态管理,可以参考官网的介绍:Simple app state management

中文网的介绍:简单的应用状态管理

Flutter 官方的两个sample:
provider_counter
provider_shopper

ChangeNotifierProvider的使用

0. 添加provider包的依赖

在pubspec.yaml中添加provider:

dependencies:flutter:sdk: flutter# Import the provider package.provider: ^3.0.0

provider包的文档:
https://pub.dev/documentation/provider/latest/
里面介绍来从2.0版本到3.0版本的迁移修改方法,
在3.0版本中,有以下Provider类型:

后续博文将逐个介绍学习各Provider的使用场景

1. 定义一个数据Model类,继承自ChangeNotifier

/// Simplest possible model, with just one field.
///
/// [ChangeNotifier] is a class in `flutter:foundation`. [Counter] does
/// _not_ depend on Provider.
class Counter with ChangeNotifier {int value = 0;void increment() {value += 1;notifyListeners();}
}

这里的ChangeNotifier其实很简单,类似于一个Observable,继承自Listenable,内部维护了一个
ObserverList <VoidCallback> _listeners,提供添加和删除listener的方法,有一个notify方法,用来通知所有的观察者(或者称为消费者Consumer)
大致源码如下:

class ChangeNotifier implements Listenable {ObserverList<VoidCallback> _listeners = ObserverList<VoidCallback>();//省略addListener、removeListener等方法@protected@visibleForTestingvoid 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,);},));}}}}

2. 使用ChangeNotifierProvider来将Model与Widget相关联

这里的ChangeNotifierProvider包裹的Widget选哪个要注意一下:

⚠️注意:ChangeNotifierProvider 放在什么位置:在需要访问它的 widget 之上,但是不要把ChangeNotifierProvider放的级别太高,因为你不希望破坏整个结构

 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.builder: (context) => Counter(),child: MyApp(),),);

请注意我们定义了一个 builder 来创建一个 Model 的实例。ChangeNotifierProvider 非常聪明,它 不会 重复实例化 Model,除非在个别场景下。如果该实例已经不会再被调用,ChangeNotifierProvider 也会自动调用 Model 的 dispose() 方法。

如果你想提供更多状态,可以使用 MultiProvider:

void main() {runApp(MultiProvider(providers: [ChangeNotifierProvider(builder: (context) => CartModel()),Provider(builder: (context) => SomeOtherClass()),],child: MyApp(),),);
}

3. 定义监听者Consumer,获取Model的值来更新UI

 body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('You have pushed the button this many times:'),// Consumer looks for an ancestor Provider widget// and retrieves its model (Counter, in this case).// Then it uses that model to build widgets, and will trigger// rebuilds if the model is updated.Consumer<Counter>(builder: (context, counter, child) => Text('${counter.value}',style: Theme.of(context).textTheme.display1,),),],),)

Consumer widget 唯一必须的参数就是 builder。当 ChangeNotifier 发生变化的时候会调用 builder 这个函数。(换言之,当你在模型中调用 notifyListeners() 时,所有和 Consumer 相关的 builder 方法都会被调用。)

builder 函数的第二个参数是 ChangeNotifier 的实例。它是我们最开始就能得到的实例。你可以通过该实例定义 UI 的内容。

第三个参数是 child,用于优化目的。如果 Consumer 下面有一个庞大的子树,当模型发生改变的时候,该子树 并不会 改变,那么你就可以仅仅创建它一次,然后通过 builder 获得该实例。

⚠️注意:最好能把 Consumer 放在 widget 树尽量低的位置上。你总不希望 UI 上任何一点小变化就全盘重新构建 widget 吧

4. 使用Provider.of来更新数据

除了像上一步中使用Consumer可以获取到当前的model数据之外,还可以使用Provider.of;
但是使用Provider.of,默认使用时,Model中的 notifyListeners() 被调用后,所有这个Model关联的Consumer的build方法都会被调用,也就是会刷新相关联的Widget;

floatingActionButton: FloatingActionButton(// Provider.of is another way to access the model object held// by an ancestor Provider. By default, even this listens to// changes in the model, and rebuilds the whole encompassing widget// when notified.//// By using `listen: false` below, we are disabling that// behavior. We are only calling a function here, and so we don't care// about the current value. Without `listen: false`, we'd be rebuilding// the whole MyHomePage whenever Counter notifies listeners.onPressed: () =>Provider.of<Counter>(context, listen: false).increment(),tooltip: 'Increment',child: Icon(Icons.add),),

⚠️注意:虽然我们可以使用 Consumer 来实现这个效果,不过这么实现有点浪费。因为我们让整体框架重构了一个无需重构的 widget。所以这里我们可以使用 Provider.of,并且将 listen 设置为 false。在 build 方法中使用上面的代码,当 notifyListeners 被调用的时候,并不会使 widget 被重构。

Flutter状态管理1-ChangeNotifierProvider的使用相关推荐

  1. Flutter 状态管理指南之 Provider

    2019 Google I/O 大会,Flutter 团队在"Pragmatic State Management in Flutter "演讲上正式介绍了 Provider.自此 ...

  2. Flutter 状态管理

    目录 一.状态管理简介 1.1 为什么需要状态管理 1.1.1 Flutter与adr/ios UI框架区别 1.1.2 状态管理框架使用场景 1.2 需要解决的问题 二.状态管理框架现有方案调研 2 ...

  3. Flutter 状态管理之Bloc上

    前言:Flutter 的状态管理插件有很多,比如 Provider,GetX 还有本篇要讲述的 Bloc .Bloc 目前最新的版本是 flutter_bloc: ^8.0.1. BLoC 依赖 St ...

  4. flutter 状态管理 flutter_bloc 的使用以及总结

    Bloc介绍 flutter_bloc 8.0,直接把mapEventToState方法去掉,需要手动注册事件处理器,不用再写if else 来判断event ,也不用写yield flutter_b ...

  5. FlyAI小课堂:Flutter 状态管理之BLoC

    在正式介绍 BLoC之前, 为什么我们需要状态管理.如果你已经对此十分清楚,那么建议直接跳过这一节. 如果我们的应用足够简单,Flutter 作为一个声明式框架,你或许只需要将 数据 映射成 视图 就 ...

  6. 【flutter-mobx】Flutter 状态管理- 使用 MobX实现计数器

    实践flutter mobx: 提示:对下面这篇掘金文章的实践,通过flutter结合 mobx 实现计数器,过程中也添加了一些处理和注释,代码放在feat/mobx下 https://juejin. ...

  7. Flutter 状态管理之Bloc下

    这篇是使用 Bloc 来实现业务逻辑与UI分离.主要就是慕课网课程列表的网络请求并且展示. 首先定义一个基础事件的类,如下: abstract class LessonEvent {} 然后我定义了3 ...

  8. flutter 局部状态和全局状态区别_Flutter状态管理

    Flutter状态管理 状态管理是声明式编程非常重要的一个概念,我们在前面介绍过Flutter是声明式编程的,也区分声明式编程和命令式编程的区别. 这里,我们就来系统的学习一下Flutter声明式编程 ...

  9. Flutter项目该如何选择状态管理?

    状态管理原则 我们在开发过程中,为了提高项目的可维护度和性能,也为了让页面UI跟数据(本地或服务端数据)有效分离的同时又能有效同步,都会让项目保持清晰的目录结构.同时启用状态管理库. 而MVVM模式已 ...

最新文章

  1. 简单jQuery实现选项框中列表项的选择
  2. linux 下使用 curl 访问带多参数,GET掉参数解决方案
  3. IBM:破解密码并不是量子计算机主要用途,不必为此担心
  4. css实现文字在横线上居中
  5. hdu 3007(最小圆覆盖)
  6. 【Linux网络编程】原始套接字实例:MAC 地址扫描器
  7. 用Python实现优先级队列
  8. hdu 2602 Bone Collector(01背包)
  9. CPU时间分片、多线程、并发和并行
  10. breakcontinue
  11. 早起 - 对我影响最大的习惯
  12. mongodb数据库调用
  13. 智能车制作——从元器件、机电系统、控制算法到完整的智能车设计|文末赠书
  14. 浅谈摄某网绕过图片水印查看下载无水印图片
  15. 谈谈认证中的黄埔军---信息安全认证(CISP与CISSP)
  16. 整型常量(基于百度及各处资料加上我的个人经验整理而成)
  17. lua php 触摸精灵,触动精灵,触摸精灵-lua脚本入门
  18. 计算机常考的快捷键,电脑常见快捷键大全
  19. vux scroller在iOS13上,一停止滑动就跳到顶部
  20. java表白 520

热门文章

  1. 韩商言求婚了!你却还不知道现男友喜欢什么类型?
  2. LoadLibrary 调用失败错误码记录
  3. 计算机图形学课件pdf版
  4. 8个时刻,老人缓一缓
  5. 用Java实现Google的“您是不是要找”功能
  6. 东信正式挂牌成立视频研究院;浪潮集团参与“东数西算”战略工程 | 全球TMT...
  7. 传聚美优品将赴美上市 公司估值超30亿美元
  8. 记录ubuntu启动卡在logo界面有鼠标进不了桌面的经历,以及安装ubuntu踩的坑
  9. 全志A40i编译RTL8192CU/RTL8192CE驱动
  10. 勇探计算机城堡教学反思,《梦幻中的城堡》美术教学反思