Flutter Provider状态管理---八种提供者使用分析
Provider
Provider
是最基本的Provider组件,可以使用它为组件树中的任何位置提供值,但是当该值更改的时候,它并不会更新UI
class UserModel {String name = "kwok";void changeName() {name = "hello";}
}return Provider<UserModel>(create: (_) => UserModel(),child: MaterialApp(debugShowCheckedModeBanner: false,home: ProviderExample(),),
);import 'package:flutter/material.dart';
import 'package:flutter_provider_example/provider_example/user_model.dart';
import 'package:provider/provider.dart';class ProviderExample extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("ProviderExample"),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Consumer<UserModel>(builder: (_, userModel, child) {return Text(userModel.name,style: TextStyle(color: Colors.red,fontSize: 30));},),Consumer<UserModel>(builder: (_, userModel, child) {return Padding(padding: EdgeInsets.all(20),child: ElevatedButton(onPressed: (){userModel.changeName();},child: Text("改变值"),),);},),],),),);}
}
运行结果
我们点击按钮的会导致模型数据改变,但是模型数据改变之后UI并没有变化也没有重建,那是因为Provider
提供者组件不会监听它提供的值的变化。
ChangeNotifierProvider
它跟Provider
组件不同,ChangeNotifierProvider
会监听模型对象的变化,而且当数据改变时,它也会重建Consumer
(消费者),下面我们给出一个示例
import 'package:flutter/material.dart';class UserModel1 with ChangeNotifier {String name = "Kwok";void changeName() {name = "hello";notifyListeners();}
}
return ChangeNotifierProvider<UserModel1>(create: (_) => UserModel1(),child: MaterialApp(debugShowCheckedModeBanner: false,home: ChangeNotifierProviderExample(),),
);
import 'package:flutter/material.dart';
import 'package:flutter_provider_example/change_notifier_provider_example/user_model1.dart';
import 'package:provider/provider.dart';class ChangeNotifierProviderExample extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("ChangeNotifierProvider"),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Consumer<UserModel1>(builder: (_, userModel, child) {return Text(userModel.name,style: TextStyle(color: Colors.red,fontSize: 30));},),Consumer<UserModel1>(builder: (_, userModel, child) {return Padding(padding: EdgeInsets.all(20),child: ElevatedButton(onPressed: (){userModel.changeName();},child: Text("改变值"),),);},),],),),);}
}
FutureProvider
简单来说,FutureProvider
用于提供在组件树中准备好使用其值时可能尚未准备好的值,主要是确保空值不会传递给任何子组件,而且FutureProvider
有一个初始值,子组件可以使用该Future
值并告诉子组件使用新的值来进行重建。
注意:
FutureProvider
只会重建一次- 默认显示初始值
- 然后显示
Future
值 - 最后不会再次重建
第一步:创建模型 这里和Provider不同的是增加了构造函数,以及changeName变成了Future,我们模拟网络请求延迟两秒后改变其值。class UserModel2{UserModel2({this.name});String? name = "Jimi";Future<void> changeName() async {await Future.delayed(Duration(milliseconds: 2000));name = "hello";} } 第二步:提供Future 我们有一个方法,就是异步获取userModel2,模拟网络请求延迟两秒执行,最后修改了name并返回UserModel2import 'package:flutter_provider_example/future_provider_example/user_model2.dart';class UserFuture {Future<UserModel2> asyncGetUserModel2() async {await Future.delayed(Duration(milliseconds: 2000));return UserModel2(name: "获取新的数据");}} 第三步:应用程序入口设置 initialData是默认值,create参数我们传了一个Future<UserModel2>,因为它接收的模型Create<Future<T>?>return FutureProvider<UserModel2>(initialData: UserModel2(name: "hello"),create: (_) => UserFuture().asyncGetUserModel2(),child: MaterialApp(debugShowCheckedModeBanner: false,home: FutureProviderExample(),), ); 第四步:使用共享数据 import 'package:flutter/material.dart'; import 'package:flutter_provider_example/future_provider_example/user_model2.dart'; import 'package:provider/provider.dart';class FutureProviderExample extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("FutureProviderExample"),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Consumer<UserModel2>(builder: (_, userModel, child) {return Text(userModel.name ?? "",style: TextStyle(color: Colors.red,fontSize: 30));},),Consumer<UserModel2>(builder: (_, userModel, child) {return Padding(padding: EdgeInsets.all(20),child: ElevatedButton(onPressed: (){userModel.changeName();},child: Text("改变值"),),);},),],),),);} }
StreamProvider
StreamProvider
提供流值,是围绕StreamBuilder
,所提供的值会在传入的时候替换掉新值。和FutureProvider
一样,主要的区别在于值会根据多次触发重新构建UI。第一步:创建模型
class UserModel3{UserModel3({this.name});String? name = "kwok";void changeName() {name = "hello";} }
第二步:提供Stream
下面这段代码类似计时器,每隔一秒钟生成一个数字
import 'package:flutter_provider_example/stream_provider_example/user_model3.dart';class UserStream {Stream<UserModel3> getStreamUserModel() {return Stream<UserModel3>.periodic(Duration(milliseconds: 1000),(value) => UserModel3(name: "$value")).take(10);}
}
第三步:应用程序入口设置
这里也有
initialData
初始值,和FutureProvider
类似,只是create
属性是获取一个Stream
流。return StreamProvider<UserModel3>(initialData: UserModel3(name: "hello"),create: (_) => UserStream().getStreamUserModel(),child: MaterialApp(debugShowCheckedModeBanner: false,home: StreamProviderExample(),), );
第四步:使用共享数据
import 'package:flutter/material.dart'; import 'package:flutter_provider_example/stream_provider_example/user_model3.dart'; import 'package:provider/provider.dart';class StreamProviderExample extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("StreamProviderExample"),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Consumer<UserModel3>(builder: (_, userModel, child) {return Text(userModel.name ?? "",style: TextStyle(color: Colors.red,fontSize: 30));},),Consumer<UserModel3>(builder: (_, userModel, child) {return Padding(padding: EdgeInsets.all(20),child: ElevatedButton(onPressed: (){userModel.changeName();},child: Text("改变值"),),);},),],),),);} }
MultiProvider
在上面的例子中我们都只是返回了一个提供者,在实际开发过程中肯定会有多个提供者,我们虽然可以采用嵌套的方式来解决,但是这样无疑是混乱的,可读性级差。这个时候强大的
MultiProvder
就产生了,我们来看下示例:第一步:创建两个模型
import 'package:flutter/material.dart';class UserModel1 with ChangeNotifier {String name = "kwok";void changeName() {name = "hello";notifyListeners();} }class UserModel4 with ChangeNotifier {String name = "kwok";int age = 18;void changeName() {name = "hello";age = 20;notifyListeners();} }
第二步:应用程序入口设置
相对于方式一这种嵌套方式设置,方式二就显得尤为简单。
方式一:嵌套设置
return ChangeNotifierProvider<UserModel1>(create: (_) => UserModel1(),child: ChangeNotifierProvider<UserModel4>(create: (_) => UserModel4(),child: MaterialApp(debugShowCheckedModeBanner: false,home: MultiProviderExample(),),), );
方式二:使用MultiProvider
return MultiProvider(providers: [ChangeNotifierProvider<UserModel1>(create: (_) => UserModel1()),ChangeNotifierProvider<UserModel4>(create: (_) => UserModel4()),/// 添加更多],child: MaterialApp(debugShowCheckedModeBanner: false,home: MultiProviderExample(),), );
第三步:使用共享数据
import 'package:flutter/material.dart'; import 'package:flutter_provider_example/change_notifier_provider_example/user_model1.dart'; import 'package:flutter_provider_example/multi_provider_example/user_model4.dart'; import 'package:provider/provider.dart';class MultiProviderExample extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("MultiProviderExample"),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Consumer<UserModel1>(builder: (_, userModel, child) {return Text(userModel.name,style: TextStyle(color: Colors.red,fontSize: 30));},),Consumer<UserModel4>(builder: (_, userModel, child) {return Text(userModel.age.toString(),style: TextStyle(color: Colors.green,fontSize: 30));},),Consumer2<UserModel1, UserModel4>(builder: (_, userModel1, userModel4, child) {return Padding(padding: EdgeInsets.all(20),child: ElevatedButton(onPressed: (){userModel1.changeName();userModel4.changeName();},child: Text("改变值"),),);},),],),),);} }
ProxyProvider
当我们有多个模型的时候,会有模型依赖另一个模型的情况,在这种情况下,我们可以使用
ProxyProvider
从另一个提供者获取值,然后将其注入到另一个提供者中。我们来看下代码演示第一步:创建两个模型
下面我们创建了两个模型
UserModel5
和WalletModel
,而WalletModel
依赖与UserModel5
,当调用WalletModel
的changeName
方法时会改变UserModel5
里面的name,当然我们在实际开发的过程中并不是这么简单,这里只是演示模型依赖时如果使用ProxyProvider
import 'package:flutter/material.dart';class UserModel5 with ChangeNotifier {String name = "keo";void changeName({required String newName}) {name = newName;notifyListeners();} }class WalletModel {UserModel5? userModel5;WalletModel({this.userModel5});void changeName() {userModel5?.changeName(newName: "JIMI");} }
第二步:应用程序入口设置
return MultiProvider(providers: [ChangeNotifierProvider<UserModel5>(create: (_) => UserModel5()),ProxyProvider<UserModel5, WalletModel>(update: (_, userModel5, walletModel) => WalletModel(userModel5: userModel5),)],child: MaterialApp(debugShowCheckedModeBanner: false,home: ProxyProviderExample(),), );
第三步:使用共享数据
import 'package:flutter/material.dart'; import 'package:flutter_provider_example/proxy_provider_example/user_model5.dart'; import 'package:flutter_provider_example/proxy_provider_example/wallet_model.dart'; import 'package:provider/provider.dart';class ProxyProviderExample extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("ProxyProviderExample"),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Consumer<UserModel5>(builder: (_, userModel, child) {return Text(userModel.name,style: TextStyle(color: Colors.red,fontSize: 30));},),Consumer<UserModel5>(builder: (_, userModel, child) {return Padding(padding: EdgeInsets.all(20),child: ElevatedButton(onPressed: (){userModel.changeName(newName: "hello");},child: Text("改变值"),),);},),Consumer<WalletModel>(builder: (_, walletModel, child) {return Padding(padding: EdgeInsets.all(20),child: ElevatedButton(onPressed: (){walletModel.changeName();},child: Text("通过代理改变值"),),);},),],),),);} }
ChangeNotifierProxyProvider
ChangeNotifierProxyProvider和
ProxyProvider
原理一样,唯一的区别在于它构建和同步ChangeNotifier
的ChangeNotifierProvider
,当提供者数据变化时,将会重构UI。下面我们给出一个例子:
- 获取书籍列表
- 获取收藏书籍列表
- 点击书籍可加入或者取消收藏
- 通过代理实时重构UI
第一步:创建两个模型
1、BookModel
BookModel
用户存储模型数据,将书籍转换成模型。class BookModel {static var _books = [Book(1, "夜的命名数"),Book(2, "大奉打更人"),Book(3, "星门"),Book(4, "大魏读书人"),Book(5, "我师兄实在太稳健了"),Book(6, "深空彼岸"),];// 获取书籍长度int get length => _books.length;// 根据ID获取书籍Book getById(int id) => _books[id -1];// 根据索引获取数据Book getByPosition(int position) => _books[position];// 更多.... }class Book {final int bookId;final String bookName;Book(this.bookId, this.bookName); }
2、BookManagerModel
BookManagerModel
主要用于管理书籍、收藏书籍、取消收藏等操作import 'package:flutter/material.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/models/book_model.dart';class BookManagerModel with ChangeNotifier {// 依赖bookModelfinal BookModel _bookModel;// 获取数据所有的IDList<int>? _bookIds;// 构造函数BookManagerModel(this._bookModel, {BookManagerModel? bookManagerModel}): _bookIds = bookManagerModel?._bookIds ?? [];// 获取所有的书List<Book> get books => _bookIds!.map((id) => _bookModel.getById(id)).toList();// 根据索引获取数据Book getByPosition(int position) => books[position];// 获取书籍的长度int get length => _bookIds?.length ?? 0;// 添加书籍void addFaves(Book book) {_bookIds!.add(book.bookId);notifyListeners();}// 删除书籍void removeFaves(Book book) {_bookIds!.remove(book.bookId);notifyListeners();} }
第二步:应用程序入口设置
return MultiProvider(providers: [Provider(create: (_) => BookModel()),ChangeNotifierProxyProvider<BookModel, BookManagerModel>(create: (_) => BookManagerModel(BookModel()),update: (_, bookModel, bookManagerModel) => BookManagerModel(bookModel),)],child: MaterialApp(debugShowCheckedModeBanner: false,home: ChangeNotifierProxyProviderExample(),), );
第三步:设置BottomNavigationBar
import 'package:flutter/material.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/pages/page_a.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/pages/page_b.dart';class ChangeNotifierProxyProviderExample extends StatefulWidget {@override_ChangeNotifierProxyProviderExampleState createState() => _ChangeNotifierProxyProviderExampleState(); }class _ChangeNotifierProxyProviderExampleState extends State<ChangeNotifierProxyProviderExample> {var _selectedIndex = 0;var _pages = [PageA(), PageB()];@overrideWidget build(BuildContext context) {return Scaffold(body: _pages[_selectedIndex],bottomNavigationBar: BottomNavigationBar(currentIndex: _selectedIndex,onTap: (index) {setState(() {_selectedIndex = index;});},items: [BottomNavigationBarItem(icon: Icon(Icons.book),label: "书籍列表"),BottomNavigationBarItem(icon: Icon(Icons.favorite),label: "收藏")],),);} }
第四步:书籍列表UI构建
import 'package:flutter/material.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/models/book_manager_model.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/models/book_model.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/widgets/book_item.dart'; import 'package:provider/provider.dart';class PageA extends StatelessWidget {@overrideWidget build(BuildContext context) {var bookModel = Provider.of<BookModel>(context);return Scaffold(appBar: AppBar(title: Text("书籍列表"),),body: ListView.builder(itemCount: bookModel.length,itemBuilder: (_, index) => BookItem(id: index + 1),),);} }
第五步:收藏列表UI构建
import 'package:flutter/material.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/models/book_manager_model.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/widgets/book_item.dart'; import 'package:provider/provider.dart';class PageB extends StatelessWidget {@overrideWidget build(BuildContext context) {var bookManagerModel = Provider.of<BookManagerModel>(context);var bookCount = bookManagerModel.length;return Scaffold(appBar: AppBar(title: Text("收藏列表"),),body: ListView.builder(itemCount: bookCount,itemBuilder: (_, index) => BookItem(id: bookManagerModel.getByPosition(index).bookId),),);} }
其他辅助封装类
import 'package:flutter/material.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/models/book_manager_model.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/models/book_model.dart'; import 'package:provider/provider.dart';class BookButton extends StatelessWidget {final Book book;BookButton({Key? key,required this.book}) : super(key: key);@overrideWidget build(BuildContext context) {var bookManagerModel = Provider.of<BookManagerModel>(context);return GestureDetector(onTap: bookManagerModel.books.contains(this.book)? () => bookManagerModel.removeFaves(this.book): () => bookManagerModel.addFaves(this.book),child: SizedBox(width: 100,height: 60,child: bookManagerModel.books.contains(this.book)? Icon(Icons.star, color: Colors.red,): Icon(Icons.star_border),),);} } import 'package:flutter/material.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/models/book_model.dart'; import 'package:flutter_provider_example/change_notifier_proxy_provider_example/widgets/book_button.dart'; import 'package:provider/provider.dart';class BookItem extends StatelessWidget {final int id;BookItem({Key? key,required this.id}) : super(key: key);@overrideWidget build(BuildContext context) {var bookModel = Provider.of<BookModel>(context);var book = bookModel.getById(id);return ListTile(leading: CircleAvatar(child: Text("${book.bookId}"),),title: Text("${book.bookName}",style: TextStyle(color: Colors.black87),),trailing: BookButton(book: book),);} }
总结
Provider
为我们提供了非常多的提供者,总共有八种。但我们比较常用的是ChangeNotifierProvider
、MultiProvider
、ChangeNotifierProxyProvider
,关于其他的提供者可根据自己的实际应用场景来。
Flutter Provider状态管理---八种提供者使用分析相关推荐
- Flutter Provider状态管理-Consumer
前言 如果对Consumer很了解的同学可以继续学习 Flutter Provider状态管理 - Selector 个人觉得Flutter的学习有三个很重要的阶段 widget的学习和使用 数据以及 ...
- flutter基于provider状态管理设置主题颜色、实现简单登录、注册功能---页面+逻辑
一.provider状态管理设置主题颜色 第一步: 安装依赖库 provider: ^4.3.2+3 第二步: 创建共享数据模型 import 'package:flutter/material.da ...
- Flutter GetX 状态管理 响应式编程(三)
在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天.每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不 ...
- Flutter GetX 状态管理 使用入门 程序计数器 (二)
在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天.每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不 ...
- Flutter - flutter_bloc状态管理
继上一篇写了Flutter - GetX状态管理,会发现其实Flutter的状态管理的框架还是比较多的,用的比较多的有flutter_bloc.MobX.GetX等,今天我就来谈一谈我学习Flutte ...
- Flutter Provider 异步通信、Provider状态管理
题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精. Flutter是谷歌推出的最新的移动开发框架. [x1]微信公众号的每日提醒 随时随记 每日积累 随心而过 [x2]各种系列的视频教程 ...
- Provider状态管理练习
一.添加依赖 provider: 6.0.5 二.创建CountModel.dart 注意:要继承ChangeNotifier import 'package:flutter/cupertino.da ...
- Flutter 对状态管理的认知与思考
前言 关于这篇文章的一些内容,我很久之前就想写的,但一直没啥源动力,就一直鸽着 这次被捷特大佬催了几次,终于把这篇文章写完了,文章里有我对状态管理的一些思考和看法,希望能引起茫茫人海中零星的共鸣... ...
- Flutter _ 状态管理指南篇,Android开发两年
),); 然后我们开始测试,点击收藏按钮,查看 rebuild 情况. Performing hot reload- Syncing files to device iPhone Xs Max- - ...
最新文章
- Node.js 安装及环境配置之 Windows 篇
- Windows安装MRTG后的配置
- hdfs文档存储服务器,一文读懂HDFS分布式存储框架分析
- Spring与其他Web框架集成
- 惠普搜客户机t5740升级硬盘_惠普暗影精灵5首测重磅来袭:更多选择 更强性能...
- 变形金刚2_变形金刚(
- 基于.NET SingalR,LayIM2.0实现的web聊天室
- UVALive 7455	Linear Ecosystem (高斯消元)
- jquery中$.each循环的跳出
- 5G NR 链路自适应 Link Adaptation
- 首发Android 13!谷歌Pixel 7 Pro渲染图曝光:后置相机模组吸睛
- linux set命令例子,学习一个 Linux 命令:declare/typeset 命令
- [讲课视频]谈谈C/C++中的整数
- 微信小程序教程、微信小程序开发资源下载汇总(6.16日更新,持续更新中……)
- 苹果5越狱教程_unc0ver5.2.0安装方法 iOS13.5用Cydia Impactor或AltStore越狱教程
- mysql 左连接 左外连接吗_数据库左连接和左外连接有区别吗
- 超越宝典汽配汽修管理系统——“维修业务”模块功能实现
- JavaScript推箱子游戏开发笔记
- ubuntu 设置静态路由_Ubuntu添加静态路由
- jQuery WeUI v0.1.0 发布了 - 微信公众账号开发者的福音
热门文章
- 腾讯马松松谈企业安全建设:安全工程化如何落到实处
- geotools学习(七)地图样式
- 基于“总价、首付、贷款年限、利息、贷款额度”信息,计算每月最低还款额度。需要能按“等额本金、等额本息”两种形式计算还款
- 互联网热门职位薪资数据采集爬虫对比报告
- tp841虚拟服务器,TP-Link新版路由器虚拟服务器(端口映射)设置方法
- StarRocks斩获「2022 掘金引力榜」年度技术品牌传播案例 Top 10!
- 绩效考核六大认识误区解析(zt)
- python字符串的定界符不能是_Python|字符串str的构造、操作(操作符、函数、方法)...
- 2022-2028全球太阳能壁灯行业调研及趋势分析报告
- 2016 国庆,不庆