【Flutter】状态管理:高级状态管理 (Riverpod, BLoC)
当项目变得更加复杂时,简单的状态管理方式(如 setState()
或 Provider
)可能不足以有效地处理应用中状态的变化和业务逻辑的管理。在这种情况下,高级状态管理框架,如 Riverpod
和 BLoC
,可以提供更强大的工具,用于处理复杂的状态流、逻辑分离以及响应式编程。
在本教程中,我们将深入学习 Riverpod
和 BLoC
这两种高级状态管理框架,理解它们的核心概念,学会如何将业务逻辑与 UI 分离,并使用 Stream
处理复杂的状态流。
Riverpod 状态管理框架
Riverpod
是由 Provider
的作者开发的一个更加灵活、强大且类型安全的状态管理框架。相比 Provider
,Riverpod
提供了更清晰的状态管理方式,同时避免了一些常见的错误和限制。它支持全局和局部的状态管理,适用于大型应用的开发。
安装 Riverpod
首先,在 pubspec.yaml
文件中添加 riverpod
依赖:
dependencies:flutter:sdk: flutterflutter_riverpod: ^2.0.0
然后运行 flutter pub get
安装依赖。
Riverpod 核心概念
在使用 Riverpod
之前,需要了解它的几个核心概念:
Provider
:是Riverpod
的基本状态提供者。它可以创建、管理并共享状态。ConsumerWidget
:用于监听Provider
并响应其状态变化。StateProvider
:提供一种简单的方式来管理和监听状态。StateNotifier
和StateNotifierProvider
:用于管理复杂的业务逻辑和状态。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';// 定义一个 StateProvider 来管理状态
final counterProvider = StateProvider<int>((ref) => 0);void main() {runApp(ProviderScope(child: MyApp(),),);
}class MyApp extends StatelessWidget { Widget build(BuildContext context) {return MaterialApp(home: CounterPage(),);}
}class CounterPage extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) {// 通过 ref 读取 counterProvider 的状态final counter = ref.watch(counterProvider);return Scaffold(appBar: AppBar(title: Text('Riverpod Counter Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('You have pushed the button this many times:'),Text('$counter',style: Theme.of(context).textTheme.headline4,),],),),floatingActionButton: FloatingActionButton(onPressed: () {// 更新状态ref.read(counterProvider.notifier).state++;},tooltip: 'Increment',child: Icon(Icons.add),),);}
}
代码详解
-
StateProvider
:counterProvider
是一个StateProvider
,它用于管理整型计数器状态。我们定义了一个初始值0
,并通过ref.watch
监听状态的变化。 -
ProviderScope
:这是Riverpod
的核心组件,用于提供上下文中可访问的状态。ProviderScope
必须在应用的最顶层。 -
ConsumerWidget
:CounterPage
继承自ConsumerWidget
,用于监听状态提供者counterProvider
,并在状态变化时重新构建 UI。 -
状态更新:
ref.read(counterProvider.notifier).state++
用于更新状态。这里我们通过read
方法获取StateProvider
的notifier
,然后修改其状态。
BLoC 状态管理框架
BLoC
(Business Logic Component)是一种基于响应式编程的状态管理模式,它通过 Stream
处理复杂的状态流,实现了业务逻辑和 UI 的完全分离。这种模式适用于大型项目,能够确保代码的可维护性和扩展性。
BLoC
的核心思想是将事件流(Event)转换为状态流(State),从而使得业务逻辑独立于界面逻辑。
安装 flutter_bloc
在 pubspec.yaml
文件中添加 flutter_bloc
包依赖:
dependencies:flutter:sdk: flutterflutter_bloc: ^8.0.0bloc: ^8.0.0
运行 flutter pub get
安装依赖。
BLoC 核心概念
BLoC
:用于处理输入的事件并输出相应的状态。它封装了业务逻辑和状态转换。Cubit
:Cubit
是BLoC
的简化版本,通常用于处理简单的状态变化。Stream
:BLoC
和Cubit
都依赖Stream
来传递状态更新。BlocProvider
和BlocBuilder
:用于提供BLoC
实例并在 UI 中监听状态变化。
示例:使用 Cubit 实现计数器
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';// 定义 Cubit,用于管理计数器状态
class CounterCubit extends Cubit<int> {CounterCubit() : super(0);void increment() => emit(state + 1); // 更新状态
}void main() {runApp(MyApp());
}class MyApp extends StatelessWidget { Widget build(BuildContext context) {return MaterialApp(home: BlocProvider(create: (context) => CounterCubit(),child: CounterPage(),),);}
}class CounterPage extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('BLoC Counter Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('You have pushed the button this many times:'),BlocBuilder<CounterCubit, int>(builder: (context, count) {return Text('$count',style: Theme.of(context).textTheme.headline4,);},),],),),floatingActionButton: FloatingActionButton(onPressed: () {// 获取 CounterCubit 实例并调用 incrementcontext.read<CounterCubit>().increment();},tooltip: 'Increment',child: Icon(Icons.add),),);}
}
代码详解
-
CounterCubit
:Cubit
是BLoC
的简化版本,用于处理简单的状态更新。这里我们定义了一个计数器Cubit
,初始状态为0
,并通过increment()
方法更新状态。 -
BlocProvider
:提供CounterCubit
实例,并使其在子组件中可访问。 -
BlocBuilder
:用于监听Cubit
的状态变化,并根据新的状态更新 UI。 -
状态更新:通过
context.read<CounterCubit>().increment()
调用Cubit
的increment
方法,更新状态。
使用 Stream 处理复杂状态流
在 BLoC
中,Stream
是核心工具,用于传递状态更新。我们可以将用户的输入事件(如点击按钮)作为 Stream
的输入,并将业务逻辑的输出作为状态流输出给 UI。
示例:BLoC 处理多种事件
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';// 定义事件
abstract class CounterEvent {}class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}// 定义 BLoC 类
class CounterBloc extends Bloc<CounterEvent, int> {CounterBloc() : super(0); Stream<int> mapEventToState(CounterEvent event) async* {if (event is Increment) {yield state + 1;} else if (event is Decrement) {yield state - 1;}}
}void main() {runApp(MyApp());
}class MyApp extends StatelessWidget { Widget build(BuildContext context) {return MaterialApp(home: BlocProvider(create: (context) => CounterBloc(),child: CounterPage(),),);}
}class CounterPage extends StatelessWidget { Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('BLoC Stream Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('You have pushed the button this many times:'),BlocBuilder<CounterBloc, int>(builder: (context, count) {return Text('$count',style: Theme.of(context).textTheme.headline4,);},),],),),floatingActionButton: Row(mainAxisAlignment: MainAxisAlignment.end,children: <Widget>[FloatingActionButton(onPressed: () {context.read<CounterBloc>().add(Increment());},tooltip: 'Increment',child: Icon(Icons.add),),SizedBox(width: 10),FloatingActionButton(onPressed: () {context.read<CounterBloc>().add(Decrement());},tooltip: 'Decrement',child: Icon(Icons.remove),),],),);}
}
代码解析
-
事件类型:
CounterEvent
是事件基类,Increment
和Decrement
是具体事件。 -
CounterBloc
类:BLoC
类负责接收事件,并使用mapEventToState
方法将事件映射为状态更新流。 -
BlocProvider
和BlocBuilder
:与之前的Cubit
示例类似,BlocProvider
提供CounterBloc
实例,BlocBuilder
监听状态流并更新 UI。
总结
通过本教程的学习,你已经掌握了 Riverpod
和 BLoC
这两种高级状态管理框架。这两种框架都适用于大型项目中的复杂状态管理,能够有效地将业务逻辑与 UI 分离,并通过响应式编程处理状态流。
- Riverpod 适合类型安全、灵活的状态管理需求,提供简单易用的 API。
- BLoC 则非常适合需要严格分离业务逻辑和 UI 的项目,特别是在需要处理复杂状态流和多种事件的情况下。
掌握这些工具,将帮助你在实际项目中更加高效地管理复杂状态,构建出高质量的 Flutter 应用。
相关文章:
【Flutter】状态管理:高级状态管理 (Riverpod, BLoC)
当项目变得更加复杂时,简单的状态管理方式(如 setState() 或 Provider)可能不足以有效地处理应用中状态的变化和业务逻辑的管理。在这种情况下,高级状态管理框架,如 Riverpod 和 BLoC,可以提供更强大的工具…...

OAK相机的RGB-D彩色相机去畸变做对齐
▌低畸变标准镜头的OAK相机RGB-D对齐的方法 OAK相机内置的RGB-D管道会自动将深度图和RGB图对齐。其思想是将深度图像中的每个像素与彩色图像中对应的相应像素对齐。产生的RGB-D图像可以用于OAK内置的图像识别模型将识别到的2D物体自动映射到三维空间中去,或者产生的…...
smartctl硬盘检查工具
一、smartctl工具简介 Smartmontools是一种硬盘检测工具,通过控制和管理硬盘的SMART(Self Monitoring Analysis and Reporting Technology),自动检测分析及报告技术)技术来实现的,SMART技术可以对硬盘的磁头单元、盘片电机驱动系统、硬盘…...
清空MySQL数据表
要清空 MySQL 数据表,您可以使用 TRUNCATE 或 DELETE 命令 使用 TRUNCATE 命令 TRUNCATE 命令用于删除表中的所有数据,并重置自增 ID(如果存在): TRUNCATE TABLE table_name;将 table_name 替换为您要清空的表的名称…...

2024年妈杯MathorCup大数据竞赛A题超详细解题思路
2024年妈杯大数据竞赛初赛整体难度约为0.6个国赛。A题为台风中心路径相关问题,为评价预测问题;B题为库存和销量的预测优化问题。B题难度稍大于A题,可以根据自己队伍情况进行选择。26日早六点之前发布AB两题相关解题代码论文。 下面为大家带来…...
Kafka系列之:Kafka集群磁盘条带划分和Kafka集群磁盘扩容详细方案
Kafka系列之:Kafka集群磁盘条带划分和Kafka集群磁盘扩容详细方案 一、lsblk命令二、Kafka节点磁盘条带化方案一三、Kafka节点磁盘条带化方案二四、理解逻辑区块LE五、查看kafka节点磁盘条带划分情况六、Kafka节点磁盘扩容一、lsblk命令 lsblk命令用于列出块设备的信息,包括磁…...

【LeetCode】修炼之路-0007- Reverse Integer (整数反转)【python】
题目 Reverse Integer Given a signed 32-bit integer x, return x with its digits reversed. If reversing x causes the value to go outside the signed 32-bit integer range [-231, 231 - 1], then return 0. Assume the environment does not allow you to store 64-b…...
【Flutter】页面布局:线性布局(Row 和 Column)
在 Flutter 中,布局(Layout)是应用开发的核心之一。通过布局组件,开发者可以定义应用中的控件如何在屏幕上排列。Row 和 Column 是 Flutter 中最常用的两种线性布局方式,用于水平和垂直排列子组件。在本教程中…...
C语言巨难题:执行操作可获得的最大总奖励 I(C语言版)
1.题目: 给你一个整数数组 rewardValues,长度为 n,代表奖励的值。 最初,你的总奖励 x 为 0,所有下标都是 未标记 的。你可以执行以下操作 任意次 : 从区间 [0, n - 1] 中选择一个 未标记 的下标 i。如果…...

【力扣】GO解决子序列相关问题
文章目录 一、引言二、动态规划方法论深度提炼子序列问题的通用解法模式 三、通用方法论应用示例:最长递增子序列(LeetCode题目300)Go 语言代码实现 四、最长连续递增序列(LeetCode题目674)Go 语言代码实现 五、最长重…...
Ubuntu20.04安装VM tools并实现主机和虚拟机之间文件夹共享
1、Ubuntu20.04安装VM tools 参考这个,很详细:Ubuntu 20.04 安装 VMwareTools 教程 2、实现主机与VMware虚拟机共享文件夹 设置共享文件夹参考:windows和虚拟机互传文件的三种方式 挂载操作参考:主机与VMware虚拟机共享文件夹&…...
Linux 学习笔记(十七)—— 文件系统
终极目标:理解 inode 和 软硬连接; 文件系统:Ext2; 文件 文件内容 文件属性; ——> 磁盘上存储的文件 存储的文件内容 存储的文件属性; Linux系统中:文件内容使用数据块存储,文件属性使用inode(固定…...
【计算机网络 - 基础问题】每日 3 题(五十八)
✍个人博客:https://blog.csdn.net/Newin2020?typeblog 📣专栏地址:http://t.csdnimg.cn/fYaBd 📚专栏简介:在这个专栏中,我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞…...

Netty入门基础:IO模型中BIO\NIO概念及区别【附演示代码】
文章目录 😀BIO💢实战demo 🌈NIO🏍Buffer核心属性核心方法 🎗Channel🎈Selector核心方法 🧨实战demo 🎨粘包与半包 😀BIO 传统IO模型,同步阻塞,每…...

vue2 使用环境变量
一. 在根目录下创建.env.xxx文件 .env 基础系统变量,无论何种环境,都可使用其中配置的值,其他环境中的变量会覆盖.env中的同名变量。 .env.development 开发环境 .env.production 生产环境 .env.staging 测试环境 二. 内容格式 vue2 使用是以…...
数据预处理
继续提取代码片段: 12. **导入iris数据集并查看前5行数据**: python from sklearn.datasets import load_iris iris load_iris() X iris.data print(iris数据集的维度为:, X.shape) print(iris数据集的前5行数据为:\n, X[:5]) …...

django宠物领养管理系统-计算机毕业设计源码26858
目录 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章小结 3 系统总体设计 3…...

使用TeamViewer远程局域网内的两台电脑
有个场景,有人还不知道TV可以局域网操作,记录一下。 主要就是修改设置,将取消激活改为接受 然后输入受控端的ip即可...

GUI简介、Swing的常用组件、java程序的运行过程、class文件、JAR、runable_jar、双括号初始化
GUI简介 GUI:图形用户界面,在计算机中采用图形的方式显示用户界面 java的GUI开发 AWT:java最早推出的GUI编程开发包,界面风格跟随操作系统SWT:eclipse就是java使用SWT开发的Swing:在AWT的基础上扩充了功能…...
@Autowired和@Resource和getBean()区别
今天遇到一个对我来说很奇葩的错误,我想在Service中注入bean,我这里使用了Autowired和Resource都不能注入,导致初始化失败,使用了getBean()方法就可以注入。从来没有遇到过这个问题。后来我查询了一下,才明白了原理。我…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...