Provider.of

Provider.of 方法是 Provider 库中最常用的获取共享数据的方法之一。它接收一个 BuildContext 对象和一个泛型类型参数 T,会查找 Widget 树中最近的一个类型为 T 的 Provider 对象,并返回它所提供的共享数据。当共享数据发生变化时,它会自动重新构建与该共享数据有依赖关系的 StatefulWidget。

模型
class UserModel with ChangeNotifier {

  String name = "Jimi";
int aa = 0; void changeName() {
aa++;
name = "hello"+aa.toString();
print(name);
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(),
), );
}
}
使用
class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("ConsumerExample"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
Provider.of<UserModel>(context).name,
style: const TextStyle(color: Colors.red, fontSize: 50),
),
Padding(
padding: EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () {
Provider.of<UserModel>(context, listen: false)
.changeName(); //listen: false 必加
},
child: Text("点击加1"),
),
)
],
),
),
);
}
}

*Consumer

Consumer 是一个轻量级的组件,用于消费共享数据并构建 UI。它接收一个 BuildContext 对象和一个 builder 函数作为参数,在 builder 函数中构建 UI,该 UI 依赖于共享数据。当共享数据发生变化时,Consumer 会自动重新构建 UI。

里面有三个属性:

  • context: 当前的上下文
  • **Provider.of(context):** 模型对象
  • child: 子组件(不需要刷新的部分)
模型
  String name = "Jimi";
int aa = 0; void changeName() {
aa++;
name = "hello$aa";
print(name);
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(),
),
);
}
}
使用
class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("ConsumerExample"),
),
body: Consumer<UserModel>(
builder: (_, UserModel userModel, child) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
userModel.name.toString(),
style: const TextStyle(color: Colors.red, fontSize: 50),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () {
userModel.changeName();
},
child: const Text("点击加1"),
),
),
Container(
//每次都需要加载
child: const Column(
children: [
Text("更多组件1"),
Text("更多组件2"),
Text("更多组件3"),
Text("更多组件4"),
Text("更多组件5"),
Text("更多组件6"),
],
),
),
child! //可选参数 1.不用每次都加载
],
),
);
},
child: const Column(
//2.不用每次都加载
children: [
Text("1更多组件1"),
Text("1更多组件2"),
Text("1更多组件3"),
Text("1更多组件4"),
Text("1更多组件5"),
],
),
),
);
}
}

Selector

Selector类和Consumer类似,只是对build调用Widget方法时提供更精细的控制,简单点来说,Selector也是一个消费者,它允许你可以从模型中准备定义哪些属性;Selector 是一个高级的组件,也用于消费共享数据并构建 UI。它接收一个 BuildContext 对象、一个 selector 函数和一个 builder 函数作为参数。selector 函数用于选择需要依赖的共享数据,当且仅当 selector 函数返回的数据发生变化时,Selector 才会重新构建 UI。这可以有效地避免不必要的重建,提高性能。

比如,用户模型中有50个属性,但是我只需要更新年龄,这样我希望不需要重建用户名、电话号码等组件;

模型
class UserModel6 with ChangeNotifier {

  String name = "Jimi";
int age = 18;
String phone = "18888888888"; void increaseAge() {
age++;
notifyListeners(); //通知注册的监听器
}
}
入口设置
class MyApp9 extends StatelessWidget {
const MyApp9({super.key}); @override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => UserModel6(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: SelectorExample(),
),
);
}
}
使用
class SelectorExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SelectorExample"),
),
body: Center(
child: Selector<UserModel6, int>(
selector: (_, userModel6) => userModel6.age,
builder: (_, age, child) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(age.toString(),
style: const TextStyle(color: Colors.red, fontSize: 30)),
child!
],
);
},
child: Padding(
padding: EdgeInsets.all(20),
child: ElevatedButton(
onPressed: () {
Provider.of<UserModel6>(context, listen: false).increaseAge();
},
child: Text("改变年龄"),
),
),
),
),
);
}
}

InheritedContext

InheritedContext 是 Provider 内部使用的一个类,用于在 Widget 树中传递共享数据的上下文。在 Provider 中,它被优化为一个轻量级的实现。通常情况下,我们不需要直接使用 InheritedContext。

三大方式:

BuildContext.read:

BuildContext.read<CountNotifier1>()可以替换掉Provider.of<CountNotifier1>(context,listen: false),它会找到CountNotifier1并返回它。

class InheritedContextExample extends StatelessWidget {

  @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("InheritedContextExample"),
),
/// read 获取值
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(context.read<CountNotifier2>().count.toString(),
style: TextStyle(
color: Colors.red,
fontSize: 50
),
),
Padding(
padding: EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () => Provider.of<CountNotifier2>(context, listen: false).increment(),
child: Text("点击加1"),
),
),
],
),
),
);
}
}
BuildContext.watch:

BuildContext.watch<CountNotifier1>()可以替换掉Provider.of<CountNotifier1>(context,listen: false),看起来和read没有什么不同,但是使用watch你就不需要在使用Consumer

class InheritedContextExample extends StatelessWidget {

  @override
Widget build(BuildContext context) { /// 重要(必须)
final countNotifier2 = context.watch<CountNotifier2>(); return Scaffold(
appBar: AppBar(
title: Text("InheritedContextExample"),
),
/// watch
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(countNotifier2.count.toString(),
style: TextStyle(
color: Colors.red,
fontSize: 50
),
),
Padding(
padding: EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () => countNotifier2.increment(),
child: Text("点击加1"),
),
),
],
),
), );
}
}
BuildContext.select:

BuildContext.select<CountNotifier1>()可以替换掉Provider.of<CountNotifier1>(context,listen: false),看起来和watch也没有什么不同,但是使用select你就不需要在使用Selector

class InheritedContextExample extends StatelessWidget {

  @override
Widget build(BuildContext context) { /// 重要
final count = context.select((CountNotifier2 countNotifier2) => countNotifier2.count); return Scaffold(
appBar: AppBar(
title: Text("InheritedContextExample"),
),
/// select
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(count.toString(),
style: TextStyle(
color: Colors.red,
fontSize: 50
),
),
Padding(
padding: EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () => Provider.of<CountNotifier2>(context, listen: false).increment(),
child: Text("点击加1"),
),
)
],
),
),
);
}
}

参考于 Flutter Provider状态管理---四种消费者使用分析 | Jimi (liujunmin.com)

Provider 四种消费者的更多相关文章

  1. Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (一) —— 总览

    Android数据的四种存储方式SharedPreferences.SQLite.Content Provider和File (一) —— 总览   作为一个完成的应用程序,数据存储操作是必不可少的. ...

  2. Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File

    作为一个完成的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别 是:SharePreference.SQLite.Content Provider和File ...

  3. Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (三) —— SharePreferences

    除了SQLite数据库外,SharedPreferences也是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息.其存储位置在/data ...

  4. Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (四) —— ContentProvider

    ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制.一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制.并且此种方式忽略了底层的数据存储实现,Cont ...

  5. Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (二) —— SQLite

    SQLite是一种转为嵌入式设备设计的轻型数据库,其只有五种数据类型,分别是: NULL: 空值 INTEGER: 整数 REAL: 浮点数 TEXT: 字符串 BLOB: 大数据 在SQLite中, ...

  6. Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (一)

    作为一个完成的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别是:SharePreference.SQLite.Content Provider和File. ...

  7. (转)Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (三) —— SharePreferences

    除了SQLite数据库外,SharedPreferences也是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息.其存储位置在/data ...

  8. ASP.NET MVC下的四种验证编程方式[续篇]

    在<ASP.NET MVC下的四种验证编程方式>一文中我们介绍了ASP.NET MVC支持的四种服务端验证的编程方式("手工验证"."标注Validation ...

  9. MSSQL Server数据库的四种连接方法和sql连接字符串

    MSSQL Server数据库的四种连接方法和sql连接字符串 分类: [ 03 ] C#(131) [ 07 ] SQL Server(68) [ 01 ] .NET(189) 今天用SQL Ser ...

  10. JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)

    1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...

随机推荐

  1. linux常见命令(五)

    用于文本内容处理的相关命令 sort uniq cut comm diff sort:对文件中数据进行排序,并将结果显示在标准输出上 命令语法:sort [选项] [文件] 选项 选项含义 -m 如果 ...

  2. CCF PTA编程培训师资认证

    考试费用: 双会员500元,任意一方单会员750元,报名考试同时成为CCF专业会员850元,非会员1000元. P/T2补考费用:双会员200元,任意一方单会员300元,非会员400元. T1补考费用 ...

  3. Python:利用math和random模块实现RSA加密算法

    实验五报告: 利用math和random模块实现RSA加密算法 实验目标 本实验的主要目标是熟悉RSA(Rivest-Shamir-Adleman)密码算法的编写,其中包括求最大公因子.模逆的扩展欧几 ...

  4. 【XXE实战】——浅看两道CTF题

    [XXE实战]--浅看两道CTF题 上一条帖子[XXE漏洞]原理及实践演示对XXE的一些原理进行了浅析,于是写了两道CTF题巩固一下,顺便也记录一下第一次写出来CTF.两道题都是在BUU上找的:[NC ...

  5. Subtree 题解

    Subtree 题目大意 给定一颗树,你可以选出一些节点,你需要对于每个点求出在强制选这个点的情况下所有选择的点联通的方案数,对给定模数取模. 思路分析 对于这种求树上每一个点方案数的题目,首先考虑换 ...

  6. Interesting Array 题解

    Interesting Array 题目大意 构造一个序列 \(a\),使其满足若干限制条件,每个限制条件是形如 l r q 的式子,其意义是:\(\&_{i=l}^ra_i=q\). 题意分 ...

  7. InnoDB 存储引擎之 Buffer Pool

    Mysql 5.7 InnoDB 存储引擎整体逻辑架构图 一.Buffer Pool 概述 InnoDB 作为一个存储引擎,为了降低磁盘 IO,提升读写性能,必然有相应的缓冲池机制,这个缓冲池就是 B ...

  8. 22. 从零用Rust编写正反向代理,一个数据包的神奇HTTP历险记!

    wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现 ...

  9. 实现金蝶云星空与赛意SMOM系统的无缝数据对接

    1. 金蝶云星空:为运营协同与管控型企业提供通用ERP服务平台 金蝶云星空是基于当今先进管理理论和数十万家国内客户最佳应用实践开发的ERP服务平台.它针对事业部制.多地点.多工厂等企业和集团公司,提供 ...

  10. Snipaste安装与使用教程

    一.下载 1.官网 下载地址 2.下载 可以直接在官网下载,也可以跳转微软仓库下载增强版的.如果是其他系统,mac在最下面,而Linux现在没有需要等待. 二.开始安装 1.下载完毕,是一压缩包绿色版 ...