游乐游手机版
首页/AI教程/文章详情

Flutter第四十七篇Provider状态管理完整图解教程第二篇

时间:2026-05-30 10:41
```html Flutter 的状态管理框架 Provider 提供了多种数据绑定方式。此前我们探讨过 ChangeNotifierProvider,今天继续深入解析其家族成员:ListenableProvider、ValueListenableProvider 和 StreamProvider。
```html

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

Flutter 47: 图解新的状态管理 Provider (二)

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 库,专用于处理异步数据流。在列表刷新、网络请求轮询等场景中非常常见。可以将其理解为一条管道:通过 StreamControllersink.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,这样基本就能顺畅运行。

```
来源:https://developer.aliyun.com/article/704470
上一篇请提供原始文章标题 下一篇高效Prompthub AI提示词创作与管理平台
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
大班体育活动PPT制作全攻略 助力孩子成长与团队合作
AI教程 · 2026-05-30

大班体育活动PPT制作全攻略 助力孩子成长与团队合作

使用情景: 如今,大班体育活动在幼儿园和小学阶段越来越普及。家长们普遍希望孩子通过这类活动锻炼体能、结交伙伴、培养团队协作能力。因此,一份生动有趣的活动PPT成了刚需——它既能帮助教师清晰呈现活动内容,又能激发孩子的参与热情,同时吸引家长关注。 不过,要设计出既有创意又信息丰富的PPT,对于教学任务

2019年度工作总结撰写指南与详尽范文提示词
AI教程 · 2026-05-30

2019年度工作总结撰写指南与详尽范文提示词

适用需求场景: 2019年度工作总结报告 2019年即将画上句号。在这一年里,得益于公司领导的悉心指导和同事们的通力协作,各项任务均按照既定节点圆满完成,同时我也积累了丰富的实践经验与工作心得。现将全年工作进行系统梳理,主要成果与经验集中在以下几个方面:

在线AI智能制作PPT网站,一键轻松应对办公挑战
AI教程 · 2026-05-30

在线AI智能制作PPT网站,一键轻松应对办公挑战

AI制作PPT的网站推荐,轻松搞定职场演示难题 在节奏飞快的职场环境中,一份专业且精美的PPT往往是高效沟通与成功汇报的核心要素。然而,从内容构思、视觉设计到版式编排,传统的PPT制作流程极为耗时费力,常常成为职场人的痛点。是否存在一种方式,能让我们从繁琐的重复劳动中抽身,将主要精力聚焦于内容本身?

如何用AI制作幼儿园大班毕业汇报PPT范文与提示词
AI教程 · 2026-05-30

如何用AI制作幼儿园大班毕业汇报PPT范文与提示词

使用情景: 每到幼儿园大班毕业季,老师们总会迎来一个甜蜜而棘手的挑战:如何制作一份既精彩纷呈又感人至深的毕业汇报PPT?这早已不只是简单的成果展示,而是对孩子们一整年学习生活的深情回溯,更是对未来的美好期许。然而,从海量素材的筛选、版式的精心打磨,到为每个孩子撰写独一无二的成长故事,每一步都让不少教

2026年第18周Python技术周刊
AI教程 · 2026-05-30

2026年第18周Python技术周刊

本周Python生态迎来多项重要进展:多个PEP获批,涉及类型系统加固、CAPI简化与打包治理;Pip26 1新增依赖冷却机制并终止对Python3 9支持;Python打包委员会正式成立,基础架构建设稳步推进。