Flutter状态管理1-ChangeNotifierProvider的使用
关于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的使用相关推荐
- Flutter 状态管理指南之 Provider
2019 Google I/O 大会,Flutter 团队在"Pragmatic State Management in Flutter "演讲上正式介绍了 Provider.自此 ...
- Flutter 状态管理
目录 一.状态管理简介 1.1 为什么需要状态管理 1.1.1 Flutter与adr/ios UI框架区别 1.1.2 状态管理框架使用场景 1.2 需要解决的问题 二.状态管理框架现有方案调研 2 ...
- Flutter 状态管理之Bloc上
前言:Flutter 的状态管理插件有很多,比如 Provider,GetX 还有本篇要讲述的 Bloc .Bloc 目前最新的版本是 flutter_bloc: ^8.0.1. BLoC 依赖 St ...
- flutter 状态管理 flutter_bloc 的使用以及总结
Bloc介绍 flutter_bloc 8.0,直接把mapEventToState方法去掉,需要手动注册事件处理器,不用再写if else 来判断event ,也不用写yield flutter_b ...
- FlyAI小课堂:Flutter 状态管理之BLoC
在正式介绍 BLoC之前, 为什么我们需要状态管理.如果你已经对此十分清楚,那么建议直接跳过这一节. 如果我们的应用足够简单,Flutter 作为一个声明式框架,你或许只需要将 数据 映射成 视图 就 ...
- 【flutter-mobx】Flutter 状态管理- 使用 MobX实现计数器
实践flutter mobx: 提示:对下面这篇掘金文章的实践,通过flutter结合 mobx 实现计数器,过程中也添加了一些处理和注释,代码放在feat/mobx下 https://juejin. ...
- Flutter 状态管理之Bloc下
这篇是使用 Bloc 来实现业务逻辑与UI分离.主要就是慕课网课程列表的网络请求并且展示. 首先定义一个基础事件的类,如下: abstract class LessonEvent {} 然后我定义了3 ...
- flutter 局部状态和全局状态区别_Flutter状态管理
Flutter状态管理 状态管理是声明式编程非常重要的一个概念,我们在前面介绍过Flutter是声明式编程的,也区分声明式编程和命令式编程的区别. 这里,我们就来系统的学习一下Flutter声明式编程 ...
- Flutter项目该如何选择状态管理?
状态管理原则 我们在开发过程中,为了提高项目的可维护度和性能,也为了让页面UI跟数据(本地或服务端数据)有效分离的同时又能有效同步,都会让项目保持清晰的目录结构.同时启用状态管理库. 而MVVM模式已 ...
最新文章
- 简单jQuery实现选项框中列表项的选择
- linux 下使用 curl 访问带多参数,GET掉参数解决方案
- IBM:破解密码并不是量子计算机主要用途,不必为此担心
- css实现文字在横线上居中
- hdu 3007(最小圆覆盖)
- 【Linux网络编程】原始套接字实例:MAC 地址扫描器
- 用Python实现优先级队列
- hdu 2602 Bone Collector(01背包)
- CPU时间分片、多线程、并发和并行
- breakcontinue
- 早起 - 对我影响最大的习惯
- mongodb数据库调用
- 智能车制作——从元器件、机电系统、控制算法到完整的智能车设计|文末赠书
- 浅谈摄某网绕过图片水印查看下载无水印图片
- 谈谈认证中的黄埔军---信息安全认证(CISP与CISSP)
- 整型常量(基于百度及各处资料加上我的个人经验整理而成)
- lua php 触摸精灵,触动精灵,触摸精灵-lua脚本入门
- 计算机常考的快捷键,电脑常见快捷键大全
- vux scroller在iOS13上,一停止滑动就跳到顶部
- java表白 520
热门文章
- 韩商言求婚了!你却还不知道现男友喜欢什么类型?
- LoadLibrary 调用失败错误码记录
- 计算机图形学课件pdf版
- 8个时刻,老人缓一缓
- 用Java实现Google的“您是不是要找”功能
- 东信正式挂牌成立视频研究院;浪潮集团参与“东数西算”战略工程 | 全球TMT...
- 传聚美优品将赴美上市 公司估值超30亿美元
- 记录ubuntu启动卡在logo界面有鼠标进不了桌面的经历,以及安装ubuntu踩的坑
- 全志A40i编译RTL8192CU/RTL8192CE驱动
- 勇探计算机城堡教学反思,《梦幻中的城堡》美术教学反思