代码

class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Example"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 使用Consumer部件获取UserModel实例并订阅其变化
Consumer<UserModel>(
builder: (_, userModel, child) {
// 在数据更新时,重新构建子部件,并显示userModel的name属性
return Text(userModel.name,
style: const TextStyle(
color: Colors.red,
fontSize: 30
)
);
},
),
// 使用Consumer部件获取UserModel实例并订阅其变化
Consumer<UserModel>(
builder: (_, userModel, child) {
// 在数据更新时,重新构建子部件,并显示一个按钮,点击按钮会调用changeName方法改变name的值
return Padding(
padding: const EdgeInsets.all(20),
child: ElevatedButton(
onPressed: (){
userModel.changeName();
},
child: const Text("改变值"),
),
);
},
),
],
),
),
);
}
}

1、Provider:

通用的提供者,可用于共享任何对象,不仅仅是状态对象。在更新时,提供者会重新构建依赖于该对象的部件。

创建模型
//1 最基本的Provider组件,可以使用它为组件树中的任何位置提供值,
//组件但是当该值更改的时候,它并不会更新UI
class UserModel extends ChangeNotifier {
String name = "jimi"; void changeName(){
name = "hellp";
print(name);
}
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
const MyApp9({super.key}); @override
Widget build(BuildContext context) {
return Provider<UserModel>(
create: (_) =>UserModel(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Example(),
),
);
}
}

2、* ChangeNotifierProvider:

用于将一个ChangeNotifier对象共享给其子孙节点,并监听状态变化。会监听模型对象的变化,而且当数据改变时,它也会重建Consumer(消费者)

创建模型
//2.ChangeNotifierProvider 它跟Provider组件不同,
//ChangeNotifierProvider会监听模型对象的变化,而且当数据改变时,
//它也会重建Consumer(消费者)
class UserModel with ChangeNotifier { String name = "Jimi"; void changeName() {
name = "hello";
notifyListeners();
}
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
const MyApp9({super.key}); @override
Widget build(BuildContext context) {
return ChangeNotifierProvider<UserModel>(
create: (_) =>UserModel(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Example(),
), );
}
}
更新数据的使用(监听数据的变化)
    void monitor() {
// 监听 Provider 参数变化
Provider.of<Parameter>(context, listen: false).addListener(() {
bookId = Provider.of<Parameter>(context, listen: false).bookId;
letterId = Provider.of<Parameter>(context, listen: false).letterId;
VTid = Provider.of<Parameter>(context, listen: false).VTid;
fetchDataFromAPI(bookId, letterId,VTid);
}); // 初始化获取数据和更新页面
bookId = Provider.of<Parameter>(context, listen: false).bookId;
letterId = Provider.of<Parameter>(context, listen: false).letterId;
VTid = Provider.of<Parameter>(context, listen: false).VTid; fetchDataFromAPI(bookId, letterId,VTid);
}

3、FutureProvider:

用于共享Future对象,通常在异步操作和数据加载中使用。

  • FutureProvider只会重建一次
  • 默认显示初始值
  • 然后显示Future
  • 最后不会再次重建
创建模型
class UserModel {

  UserModel({required this.name});

  String name = "Jimi";

  Future<void> changeName() async {
print(name);
await Future.delayed(const Duration(milliseconds: 2000)); //模拟网络请求延迟两秒后改变其值
name = "hello";
print(name);
}
}
class UserFuture {
Future<UserModel> asyncGetUserModel2() async {
await Future.delayed(const Duration(milliseconds: 6000));
return UserModel(name: "获取新的数据");
}
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
const MyApp9({super.key}); @override
Widget build(BuildContext context) {
return FutureProvider<UserModel>(
create: (_) =>UserFuture().asyncGetUserModel2(),
initialData: UserModel(name: "hello1"), //必传 不传报错
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Example(),
),
);
}
}

4、StreamProvider:

用于共享流(Stream)对象,可以是Dart中的任何流。和FutureProvider一样,主要的区别在于值会根据多次触发重新构建UI。

创建模型
//4、StreamProvider提供流值,是围绕StreamBuilder,所提供的值会在传入的时候替换掉新值。
//和FutureProvider一样,主要的区别在于值会根据多次触发重新构建UI。
class UserModel {
UserModel({required this.name});
String name = "Jimi"; void changeName() {
name = "hello";
}
} //每隔一秒钟生成一个数字
class UserStream { Stream<UserModel> getStreamUserModel() {
return Stream<UserModel>.periodic(const Duration(milliseconds: 1000),
(value) => UserModel(name: "$value")
).take(10);
}
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
const MyApp9({super.key}); @override
Widget build(BuildContext context) {
return StreamProvider<UserModel>(
create: (_) => UserStream().getStreamUserModel(),
initialData: UserModel(name: "hello1"), //必传 不传报错
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Example(),
),
);
}
}

5、* MultiProvider

在实际开发过程中肯定会有多个提供者,我们虽然可以采用嵌套的方式来解决,但是这样无疑是混乱的,

可读性级差。这个时候强大的MultiProvder就产生了;用于在应用程序的根部层次上为子树中的多个小部件提供数据共享;

创建模型
class UserModel1 with ChangeNotifier {

  String name = "Jimi";

  void changeName() {
name = "hello";
notifyListeners();
}
} class UserModel4 with ChangeNotifier { String name = "Jimi";
int age = 18; void changeName() {
name = "hello";
age = 20;
notifyListeners();
}
}
应用程序入口设置
return MultiProvider(
providers: [
ChangeNotifierProvider<UserModel1>(create: (_) => UserModel1()),
ChangeNotifierProvider<UserModel4>(create: (_) => UserModel4()),
/// 添加更多
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: MultiProviderExample(),
),
);
使用数据
class MultiProviderExample extends StatelessWidget {
@override
Widget 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("改变值"),
),
);
},
),
],
),
),
);
}
}

6、ProxyProvider:

用于根据其他提供者的值计算新值,并将新值共享给下游部件。

当我们有多个模型的时候,会有模型依赖另一个模型的情况,在这种情况下,

我们可以使用ProxyProvider从另一个提供者获取值,然后将其注入到另一个提供者中。

创建模型
class UserModel5 with ChangeNotifier {

  String name = "Jimi";

  void changeName({required String newName}) {
name = newName;
notifyListeners();
}
} class WalletModel { UserModel5? userModel5; WalletModel({this.userModel5}); void changeName() {
userModel5?.changeName(newName: "JIMI");
}
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
const MyApp9({super.key}); @override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<UserModel5>(create: (_) => UserModel5()),
ProxyProvider<UserModel5, WalletModel>(
update: (_, userModel5, walletModel) => WalletModel(userModel5: userModel5),
)
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: ProxyProviderExample(),
),
);
}
}
使用数据
class ProxyProviderExample extends StatelessWidget {
@override
Widget 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: const 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("通过代理改变值"),
),
);
},
),
],
),
),
);
}
}

7、* ChangeNotifierProxyProvider

ProxyProvider原理一样,唯一的区别在于它构建和同步ChangeNotifierChangeNotifierProvider,当提供者数据变化时,将会重构UI。

创建模型

1.

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.

class BookManagerModel with ChangeNotifier {

  // 依赖bookModel
final BookModel _bookModel; // 获取数据所有的ID
List<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(),
),
);
使用数据

1.

class ChangeNotifierProxyProviderExample extends StatefulWidget {
@override
_ChangeNotifierProxyProviderExampleState createState() => _ChangeNotifierProxyProviderExampleState();
} class _ChangeNotifierProxyProviderExampleState extends State<ChangeNotifierProxyProviderExample> { var _selectedIndex = 0;
var _pages = [PageA(), PageB()]; @override
Widget 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: "收藏"
)
],
),
);
}
}

2.

class PageA extends StatelessWidget {
@override
Widget 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),
),
);
}
}

3.

class PageB extends StatelessWidget {
@override
Widget 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),
),
);
}
}

4.

class BookButton extends StatelessWidget {

  final Book book;

  BookButton({
Key? key,
required this.book
}) : super(key: key); @override
Widget 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),
),
);
}
}

5.

class BookItem extends StatelessWidget {

  final int id;

  BookItem({
Key? key,
required this.id
}) : super(key: key); @override
Widget 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),
);
}
}

ListenableProxyProvider:

ListenableProxyProviderListenableProvider的一个变体,但是在使用上和ChangeNotifierProvider效果惊人的一致

此参考于Flutter Provider状态管理---八种提供者使用分析-腾讯云开发者社区-腾讯云 (tencent.com)

Provider的八种提供者的更多相关文章

  1. http 中定义的八种请求的介绍

    在http1.1协议中,共定义了8种可以向服务器发起的请求(这些请求也叫做方法或动作),本文对这八种请求做出简要的介绍: 1.PUT:put的本义是推送 这个请求的含义就是推送某个资源到服务器,相当于 ...

  2. Web开发必知的八种隔离级别

    ACID性质是数据库理论中的奠基石,它定义了一个理论上可靠数据库所必须具备的四个性质:原子性,一致性,隔离性和持久性.虽然这四个性质都很重要,但是隔离性最为灵活.大部分数据库都提供了一些可供选择的隔离 ...

  3. 【转】Java八种基本数据类型的比较及其相互转化

    java中有且仅有八种基本数据类型,记住就行,共分为四类: 第一类:整型-->byte     short      int     long 第二类:浮点-->float    doub ...

  4. Javascript刷新页面的八种方法

    /** * Javascript刷新页面的八种方法 * 说明一下,jQuery没有发现刷新页面的方法. */ 1 history.go(0) 2 location.reload() 3 locatio ...

  5. Selenium Webdriver元素定位的八种常用方式

    楼主原创,欢迎学习和交流,码字不容易,转载请注明出处,谢谢. 在使用selenium webdriver进行元素定位时,通常使用findElement或findElements方法结合By类返回的元素 ...

  6. Linux 的shell 字符串截取很有用。有八种方法。

    一 Linux 的字符串截取很有用.有八种方法. 假设有变量 var=http://www.linuxidc.com/123.htm 1  # 号截取,删除左边字符,保留右边字符. echo ${va ...

  7. Linux下进程通信的八种方法

    Linux下进程通信的八种方法:管道(pipe),命名管道(FIFO),内存映射(mapped memeory),消息队列(message queue),共享内存(shared memory),信号量 ...

  8. Delphi过程函数传递参数的八种方式

    今天一同事问我为什么有些过程函数里面有Var而有些没有,不解,遂到网上百度,得解.快哉,快哉. 在Delphi过程.函数中传递参数几个修饰符为Const.Var.Out.另一种不加修饰符的为默认按值传 ...

  9. 使用八种牛云存储解决方案ios7.1的app部署问题

    使用八种牛云存储解决方案ios7.1的app部署问题 一个.问题叙述性说明 开发完ios版本号的app.须要将.ipa文件和.plist文件打包上传,供用户下载,在线安装.用户安装过程简单描写叙述例如 ...

  10. LVS负载均衡的三种模式和八种算法总结

    三种LVS负载均衡模式 调度器的实现技术中,IP负载均衡技术是效率最高的,IP虚拟服务器软件(IPVS)是在linux内核中实现的。 LVS负载均衡模式---1.NAT模式 NAT用法本来是因为网络I ...

随机推荐

  1. 使用 TensorFlow 进行机器学习

    使用 TensorFlow 进行机器学习 这是使用 TensorFlow 进行机器学习的官方代码存储库. 使用 TensorFlow(Google 最新.最好的机器学习库)开始进行机器学习. 概括 第 ...

  2. BGP路由协议学习一

    转载请注明出处: 1.BGP的特点: BGP使用TCP作为其传输层协议(端口号为179),使用触发式路由更新,而不是周期性路由更新. BGP能够承载大批量的路由信息,能够支撑大规模网络. BGP提供了 ...

  3. 2023-10-18:用go语言,给定一个数组arr,长度为n,表示有0~n-1号设备, arr[i]表示i号设备的型号,型号的种类从0~k-1,一共k种型号, 给定一个k*k的矩阵map,来表示型号

    2023-10-18:用go语言,给定一个数组arr,长度为n,表示有0~n-1号设备, arr[i]表示i号设备的型号,型号的种类从0~k-1,一共k种型号, 给定一个k*k的矩阵map,来表示型号 ...

  4. Vue源码学习(十二):列队处理(防抖优化,多次调用,只处理一次)

    好家伙, 本篇讲的是数据更新请求列队处理 1.一些性能问题 数据更新的核心方法是watcher.updata方法 实际上也就是vm._updata()方法, vm._updata()方法中的patch ...

  5. 【虹科干货】Redis Enterprise vs ElastiCache——如何选择缓存解决方案?

    使用Redis 或 Amazon ElastiCache 来作为缓存加速已经是业界主流的解决方案,二者各有什么优势?又有哪些区别呢? 为了提高 Web 应用程序和数据驱动服务的性能与效率,使用 Red ...

  6. 虹科喜报 | 虹科技术工程师【国内首批】拿下Redis认证开发者证书!

    要说虹科数据库技术工程师有多强悍,认证考试2022年12月上线,次年2月就以全国首批速度强势通过考试,并于两周后正式收到[Redis认证开发人员]证书! 虹科小云忍不住浅浅炫耀一下: 或许大家对Red ...

  7. Unity csc.rsp文件

    试验版本 Unity2020.3 编译符号,就是#if UNITY_ANDROID这个东西,在处理多平台多分支的情况下挺有用的,但是在ProjectSettings里面设置比较麻烦,不主动代码调用保存 ...

  8. 我与Vue.js 2.x 的七年之痒

    --过去日子的回顾(这是个副标题) --其实这是篇广告软文(这是个副副标题) 以下是一些牢骚和感悟,不感兴趣的可以滑倒最下面,嘻嘻. 每每回忆起从前,就感觉时间飞逝,真切的感受到了那种课本中描述的白驹 ...

  9. 2023 SHCTF-校外赛道 Crypto—Wp

    WEEK1 立正 wl hgrfhg 4gNUx4NgQgEUb4NC64NHxZLg636V6CDBiDNUHw8HkapH :jdoi vl vlkw ~xrb wd nrrT Y: 凯撒解密,偏 ...

  10. 字符串表达式计算(a+b/(a-b))的思路与实践

    前言 为满足业务需要,需要为项目中自定义模板添加一个计算字段的组件,通过设置字符串表达式,使用时在改变表达式其中一个字段的数据时,自动计算另外一个字段的值. 本篇为上篇,介绍原理,简单实现一个工具,输 ...