【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()方法就可以注入。从来没有遇到过这个问题。后来我查询了一下,才明白了原理。我…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
