Flutter第四十七篇Provider状态管理完整图解教程第二篇
Flutter 的状态管理框架 Provider 提供了多种数据绑定方式。此前我们探讨过 ChangeNotifierProvider,今天继续深入解析其家族成员:ListenableProvider、ValueListenableProvider 和 StreamProvider。虽然名称各异,但核心逻辑高度一致:先绑定数据,再获取数据。

ListenableProvider 方式
1. 数据绑定
首先来看构造器方式:ListenableProvider({Key key, @required ValueBuilder builder, Disposer dispose, Widget child })。通过 builder 创建一个可监听的对象,当该 Provider 从 Widget Tree 中移除时,会自动调用 dispose 释放资源。builder 参数不能为空,否则会直接报错。以下是一个简单示例:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListenableProvider(
builder: (_) => User('Flutter', 0),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Peovider Demo')
)
);
}
}
另一种是 .value 方式,直接将现成的 listenable 对象传入:
ListenableProvider.value({
Key key,
@required T listenable,
Widget child
})
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListenableProvider.value(
listenable: User('Flutter', 0),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Peovider Demo')
)
);
}
}
2. 获取数据
在数据获取方面,不同 Provider 的用法几乎一致,主要有两种常见方式。
方式一:Provider.of(context)
class ProviderText extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of(context);
return Text('${user.getName}');
}
}
方式二:Consumer Widget 构造器
class ProviderText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, user, _) {
return Text(user.getName);
}
);
}
}
两种方式都能获取数据,Consumer 的优势在于只在 builder 内部触发重建,性能控制更加精细。
ValueListenableProvider 方式
使用 ValueListenableProvider 时,绑定的数据类必须继承自 ValueNotifier,并实现其构造方法。这样便可通过操作 value 来触发更新。例如,创建一个 Person 实体类:
// 基本数据类型
class StringBean extends ValueNotifier {
StringBean(String value) : super(value);
}
// 自定义实体类
class Person extends ValueNotifier {
Person(User value) : super(value);
String get getPersonName => value.name;
void setPersonName(String name) {
value.name = name;
notifyListeners();
}
}
1. 绑定数据
构造器方式:ValueListenableProvider({Key key, @required ValueBuilder> builder, UpdateShouldNotify updateShouldNotify, Widget child }),builder 同样不能为空。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ValueListenableProvider(
builder: (_) => Person(User('person', 101)),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Peovider Demo')
)
);
}
}
.value 方式:ValueListenableProvider.value({Key key, @required ValueListenable valueListenable, UpdateShouldNotify updateShouldNotify, Widget child })
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ValueListenableProvider.value(
valueListenable: Person(User('person', 101)),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Peovider Demo')
)
);
}
}
2. 获取数据
同样是 Provider.of 和 Consumer 这两种方式,此处不再重复贴代码。唯一需要注意的是,更新数据类中的 value 时必须手动调用 notifyListeners(),否则界面不会刷新。
class ProviderText extends StatelessWidget {
@override
Widget build(BuildContext context) {
final number = Provider.of(context);
final person = Provider.of(context);
return Center(
child: Column(
children: [
Text('${number.toString()}==${person.getName}'),
Consumer(
builder: (context, user, _) {
return Text(user.getName);
}
)
]
)
);
}
}
StreamProvider 方式
1. Stream 简介
Stream 来自 Dart:async 库,专用于处理异步数据流。在列表刷新、网络请求轮询等场景中非常常见。可以将其理解为一条管道:通过 StreamController 的 sink.add() 往管道里推送数据,再用 stream 获取处理后的结果。单 stream 与多 stream 的区别后续再详细讨论,先看看如何用它进行状态管理。
2. 绑定数据
构造器方式:StreamProvider({Key key, @required ValueBuilder> builder, T initialData, ..., Widget child })。务必在 initialData 中提供一个初始值,否则界面会显示为空。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamProvider(
builder: (_) => StreamController(),
initialData: Teacher('Teacher', 101),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Peovider Demo')
)
);
}
}
class Teacher {
var tname;
var tage;
Teacher(this.tname, this.tage);
}
// 在 TextField 中触发更新
Expanded(
child: TextField(
onChanged: (changed) {
teacher.tname = changed;
teacher.tage = 150;
StreamController().sink.add(teacher);
},
controller: _phonecontroller,
decoration: InputDecoration(
hintText: '请输入用户名',
suffixIcon: IconButton(
icon: Icon(Icons.clear, color: Colors.black45),
onPressed: () { _phonecontroller.clear(); }
)
)
)
)
.value 方式:直接传入一个 stream,同样需要 initialData。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamProvider.value(
stream: StreamController().stream,
initialData: Teacher('Teacher', 101),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Peovider Demo')
)
);
}
}
3. 获取数据
class ProviderText extends StatelessWidget {
@override
Widget build(BuildContext context) {
final teacher = Provider.of(context);
return Center(
child: Column(
children: [
Text('${teacher.tname}'),
Consumer(
builder: (context, teacher, _) {
return Text('${teacher.tname}==${teacher.tage}');
}
)
]
)
);
}
}
小结
结合上一节的 ChangeNotifierProvider 来看,这几个 Provider 的本质实际上高度相似。翻阅源码即可发现:
class ChangeNotifierProvider
extends ListenableProvider
implements SingleChildCloneableWidget {}
class ChangeNotifier implements Listenable {}
class ValueListenableProvider
extends AdaptiveBuilderWidget, ValueNotifier>
implements SingleChildCloneableWidget {}
class ValueNotifier extends ChangeNotifier implements ValueListenable {}
ChangeNotifierProvider 实际上是 ListenableProvider 的子类,因为 ChangeNotifier 实现了 Listenable 接口。而 ValueNotifier 又继承自 ChangeNotifier,因此 ValueListenableProvider 与 ChangeNotifierProvider 在很多场景下可以互换使用。区别在于绑定的数据类需要继承不同的父类:
class User with ChangeNotifier {}
class Person extends ValueNotifier {}
无论使用哪种 Provider,只要采用 .value 绑定方式,都应在 dispose 中关闭对应的 listener,以防止内存泄漏:
@override
void dispose() {
stream.dispose();
super.dispose();
}
Provider 的五种方式(ChangeNotifierProvider、ListenableProvider、ValueListenableProvider、StreamProvider 以及基础的 Provider),经过实践可以发现它们的设计思想非常统一:通过构造器绑定或值绑定,然后利用 Provider.of 或 Consumer 获取数据。当遇到复杂的实体类时,记得让其继承对应的 Listenable 或 ValueNotifier,并妥善处理 dispose,这样基本就能顺畅运行。
```
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
AI高效生成大班科学实验教学PPT下载 提升课堂质量与趣味性
```html 对于众多教师而言,大班教学既是日常挑战,也是必须面对的常态。当教室内坐着几十甚至上百名满怀期待的学生时,如何高效准备一堂既生动清晰又能牢牢抓住所有人注意力的课程?PPT 往往是那位不可或缺的“得力助手”。然而,难题也随之浮现:内容要充实,设计需美观,还要贴合不同教学主题——若从头自行
AI提升班会质量:PPT主题总结与未来计划范文
使用情景 在校园生活中,主题班会是班级凝聚力的重要体现,堪称一场“全员聚会”。同学们齐聚一堂,交流学习心得、分享生活体会,同时回顾和反思近期的整体表现。然而,每当提到“主题班会”,不少同学便会感到些许压力:如何准备?怎样才能将内容整理得既有条理、有深度,又不失趣味性?这时,PPT便成为了高效组织的得
实测ToDesk AI对比QClaw:更省额度回答更详细
前言 最近一段时间,我连续体验了几款主打“Claw”能力的桌面智能助手,最初只是想看看它们是否只是“披着AI外壳的聊天工具”。然而,真正上手体验后,感受非常明确:ToDesk AI(ToClaw)更像一个能够直接落地执行任务的桌面助手,而不只是一个会聊天、能生成内容的模型入口。 很多人在评估这类产品
大班幼儿教育PPT制作免费技巧轻松掌握告别烦恼
使用情景 在幼儿园大班的教学场景中,PPT早已成为老师们不可或缺的课堂助手。无论是日常的课件讲解、主题活动的组织,还是家长会上的总结汇报,一份优质的PPT都能让信息传递更加直观,同时有效吸引孩子们的注意力。 不过,要想把大班PPT做得既美观又实用,确实需要花费不少心思。内容既要丰富有趣,视觉上又要具
2026最新版Claude Opus 4.7国内使用全攻略:价格不变能力翻倍
比Opus 4 6更强的新一代模型Opus 4 7终于正式发布。就在OpenAI不断扩展Codex功能的同时,Anthropic迅速推出了Opus 4 7——而且这次带来的确实是实质性升级。(目前已经全量上线,用户可以直接上手体验。)那么,Opus 4 7究竟有哪些突破?先给个结论:这不是一次简单的
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

