Flutter鸿蒙next 使用 BLoC 模式进行状态管理详解

1. 引言

在 Flutter 中,随着应用规模的扩大,管理应用中的状态变得越来越复杂。为了处理这种复杂性,许多开发者选择使用不同的状态管理方案。其中,BLoC(Business Logic Component)模式作为一种流行的状态管理方法,因其将应用的业务逻辑与 UI 层分离而广泛应用。

本文将详细介绍如何在 Flutter 中使用 BLoC 模式进行状态管理,涵盖基本概念、实现步骤及代码示例,同时进行深入的代码解释,帮助开发者理解这一模式的精髓。

2. 什么是 BLoC 模式?

BLoC 是一种将业务逻辑从 UI 层分离的模式。它基于 Streams(流)和 Sinks(输入)的概念,将状态管理和 UI 更新通过流式的方式来实现。通过这种方式,UI 层通过监听数据流(Stream)来获取状态更新,避免了状态直接与 UI 层耦合,提高了代码的可维护性和可测试性。

核心组件:

  • Event:用户或系统触发的事件,代表一种动作或请求。
  • State:UI 显示的当前状态,通常是数据的一个集合。
  • Bloc:接收事件并转换为状态的核心业务逻辑组件。

Bloc 模式的核心原则就是 通过事件驱动状态的更新,并且 UI 层只关心状态的变化,而不关心事件的处理过程。

3. 使用 BLoC 的流程

使用 BLoC 模式的基本流程大致如下:

  1. 创建 Event 和 State 类:首先,定义一些 Event 和 State 类。
  2. 创建 Bloc 类:Bloc 类用于处理事件和状态之间的映射。
  3. 提供 Bloc:在 UI 中通过 BlocProvider 提供 Bloc 实例,确保其生命周期的管理。
  4. 通过 BlocBuilder 或 BlocListener 更新 UI:UI 通过监听状态变化来更新界面。

4. 代码示例

接下来,创建一个简单的计数器应用,通过 BLoC 模式管理计数器的增减操作。

代码结构:

  • CounterEvent:定义可能的用户操作事件。
  • CounterState:定义计数器的状态。
  • CounterBloc:处理事件并输出状态。

代码实现:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';// 1. 定义 Event
abstract class CounterEvent {}class IncrementEvent extends CounterEvent {}class DecrementEvent extends CounterEvent {}// 2. 定义 State
class CounterState {final int counter;CounterState({required this.counter});
}// 3. 定义 Bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {CounterBloc() : super(CounterState(counter: 0));@overrideStream<CounterState> mapEventToState(CounterEvent event) async* {if (event is IncrementEvent) {yield CounterState(counter: state.counter + 1);} else if (event is DecrementEvent) {yield CounterState(counter: state.counter - 1);}}
}// 4. 主程序界面
void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(home: BlocProvider(create: (context) => CounterBloc(),child: CounterPage(),),);}
}class CounterPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('BLoC Counter')),body: Center(child: BlocBuilder<CounterBloc, CounterState>(builder: (context, state) {return Column(mainAxisAlignment: MainAxisAlignment.center,children: [Text('Counter Value: ${state.counter}', style: TextStyle(fontSize: 30)),Row(mainAxisAlignment: MainAxisAlignment.center,children: [ElevatedButton(onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),child: Text('Increment'),),SizedBox(width: 10),ElevatedButton(onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),child: Text('Decrement'),),],)],);},),),);}
}

5. 代码详细解释

1. 定义 Event 类

abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}

CounterEvent 是一个抽象类,所有事件类型都继承自该类。我们定义了两个具体的事件:IncrementEventDecrementEvent,分别表示计数器增加和减少。

2. 定义 State 类

class CounterState {final int counter;CounterState({required this.counter});
}

CounterState 用于表示计数器的状态,包含一个名为 counter 的整数变量,表示当前计数值。State 负责存储应用的状态,它是 BLoC 模式的核心。

3. 定义 Bloc 类

class CounterBloc extends Bloc<CounterEvent, CounterState> {CounterBloc() : super(CounterState(counter: 0));@overrideStream<CounterState> mapEventToState(CounterEvent event) async* {if (event is IncrementEvent) {yield CounterState(counter: state.counter + 1);} else if (event is DecrementEvent) {yield CounterState(counter: state.counter - 1);}}
}

CounterBloc 是处理业务逻辑的核心部分,继承自 Bloc<CounterEvent, CounterState>。在构造函数中,我们初始化了计数器状态为 0。mapEventToState 方法用于处理事件并将状态转换为新的状态。例如,当接收到 IncrementEvent 时,计数器的值加 1,并通过 yield 关键字返回一个新的 CounterState

4. 提供 Bloc 并更新 UI

class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(home: BlocProvider(create: (context) => CounterBloc(),child: CounterPage(),),);}
}

BlocProvider 用于提供 CounterBloc 实例,确保它在 widget 树中是可访问的。在这里,我们将 CounterBloc 提供给 CounterPage 进行状态管理。

BlocBuilder<CounterBloc, CounterState>(builder: (context, state) {return Column(children: [Text('Counter Value: ${state.counter}'),Row(children: [ElevatedButton(onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),child: Text('Increment'),),ElevatedButton(onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),child: Text('Decrement'),),],),],);},
)

BlocBuilder 监听 CounterBloc 输出的 CounterState,并根据 state 更新 UI。点击按钮时,通过 context.read<CounterBloc>().add() 来触发相应的事件,从而更新计数器的状态。

6. 总结

通过 BLoC 模式,我们成功将业务逻辑从 UI 层分离,使得应用的状态管理更加清晰、可维护。BLoC 模式的核心思想是通过事件驱动状态的变化,UI 只需要关注状态的变化,而不需要直接操作状态或事件,降低了组件之间的耦合性。

这种模式特别适合于需要管理大量复杂状态的应用,例如社交媒体、新闻应用等,通过合理的事件与状态划分,可以实现高效的 UI 更新和良好的代码结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/466127.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker+mysql配置

拉取mysql docker pull mysqlmysql配置 创建存储文件夹 mkdir -p /home/mysql/{date,conf}在conf文件中配置my.cnf sudo vim my.cnfmy.cnf具体配置 [mysqld] #Mysql服务的唯一编号 每个mysql服务Id需唯一 server-id1#服务端口号 默认3306 port3306#mysql安装根目录&#x…

qt QHeaderView详解

1、概述 QHeaderView 是 Qt 框架中的一个类&#xff0c;它通常作为 QTableView、QTreeView 等视图类的一部分&#xff0c;用于显示和管理列的标题&#xff08;对于水平头&#xff09;或行的标题&#xff08;对于垂直头&#xff09;。QHeaderView 提供了对这些标题的排序、筛选…

删除 需要来自XXXX的权限才能对此文件夹进行更改 文件的解决办法

如果你也是&#xff1a; 如果你也有类似上面的问题&#xff0c;这篇文章算是你看对了&#xff0c;哦哟&#xff01; 我的牙齿现在是怨灵的牙齿&#xff0c;可以啃下一头牛。 翻遍千山万水&#xff0c;咱们也是终于取到真经了家人们。 首先下一个everything好吗 甩一个官网链…

题目练习之二叉树那些事儿(续集)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ 这一篇博客我们继…

本地Docker部署ZFile网盘打造个人云存储,告别公共网盘让你数据安全感爆棚

文章目录 前言1.关于ZFile2.本地部署ZFile3.ZFile本地访问测试4.ZFile的配置5.cpolar内网穿透工具安装6.创建远程连接公网地址7.固定ZFile公网地址 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker本地部署ZFile文件管理系统&#xff0c;并结合cpolar内网穿透工具实现远程…

职场逆袭!学会管理上司,你也能成为职场赢家

书友们&#xff0c;不要错过了&#xff01;我挖到了一本真正让我彻夜难眠的小说&#xff0c;情节跌宕起伏&#xff0c;角色鲜活得就像从书里跳出来陪你聊天。每一页都是新的惊喜&#xff0c;绝对让你欲罢不能。要是你也在寻找那种让人上瘾的阅读体验&#xff0c;这本书就是你的…

LangChain Ollama实战文献检索助手(三)思维链COT、思维树TOT和思维网NOT

大模型的思考方式有时候并不尽人意。我们可以在提示词中引导大模型如何拆分任务&#xff0c;按部就班地思考。 一、思维链 思维链是引导模型一步一步地思考&#xff0c;分为Zero-Shot CoT和Few-Shot CoT。Zero-Shot CoT就是著名的Let’s think step by step。Few-Shot CoT是对…

ASP页面改为UTF-8编码后,刷新页面不定时中文输出乱码终极解决方案

IIS7下的ASP页面&#xff0c;改为Utf-8编码后&#xff0c;Html部分的中文显示正常&#xff0c;但是由 Response.Write 输出的中文字符&#xff0c;在不特定的时间会变成乱码&#xff0c;一开始以为是浏览器问题&#xff0c;测试了多个浏览器故障依旧不定时出现&#xff1a; &l…

Spring底层源码(一)

Spring的入门代码&#xff1a; public class XmlTest {public static void main(String[] args) {//构造一个容器.ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext("springTest.xml");//从容器中获取Bean对象UserService userService …

理解Web登录机制:会话管理与跟踪技术解析(二)-JWT令牌

JWT令牌是一种用于安全地在各方之间传递信息的开放标准&#xff0c;它不仅能够验证用户的身份&#xff0c;还可以安全地传递有用的信息。由于其结构简单且基于JSON&#xff0c;JWT可以在不同的系统、平台和语言间无缝传递&#xff0c;成为现代Web开发中不可或缺的一部分。 文章…

SpringBoot源码解析(二):引导上下文DefaultBootstrapContext

SpringBoot源码系列文章 SpringBoot源码解析(一)&#xff1a;SpringApplication构造方法 SpringBoot源码解析(二)&#xff1a;引导上下文DefaultBootstrapContext 目录 前言一、入口二、DefaultBootstrapContext1、BootstrapRegistry接口2、BootstrapContext接口3、DefaultBo…

运维高可用架构设计

一、硬件 1、服务器 2、网络架构 二、软件 1、基础组件 组件名称 高可用方式 最少节点数 负载均衡(Tenginx) corsyncpacemaker互为主备 多组集群通过DNS轮循实现一个大集群 2DNS主从集群2RabbitMQ原生HA镜像集群3Zookeeper原生分布式集群3Kafka原生分布式集群3ES原生分布式集…

C++之vector类的模拟实现

片头 嗨~小伙伴们&#xff0c;今天我们来一起学习关于C的vector类的模拟实现&#xff0c;准备好了吗&#xff1f;咱们开始咯~ 一、基本框架 namespace bit {template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;// 针对const修…

MyBatis 返回 Map 或 List<Map>时,时间类型数据,默认为LocalDateTime,响应给前端默认含有‘T‘字符

一、问题 MyBatis 返回 Map 或 List时&#xff0c;时间类型数据&#xff0c;默认为LocalDateTime Springboot 响应给前端的LocalDateTime&#xff0c;默认含有’T’字符&#xff0c;如何统一配置去掉 二、解决方案 1、pom.xml 增加依赖&#xff08;2024.11.6 补充&#xff…

数据结构之二叉树前序,中序,后序习题分析(递归图)

1.比较相同的树 二叉树不能轻易用断言&#xff0c;因为树一定有空 2.找结点值 3.单值二叉树 4.对称二叉树 5.前序遍历

如何使用gewe开发微信机器人

[Gewe](微信管理系统)&#xff0c;个人微信**开源框架&#xff0c;支持二次开发、任意语言都可接入&#xff0c;Restful API接入。 gewe框架优势&#xff1a; - 简单易用&#xff0c;无接入难度&#xff0c;区别于其它开源项目&#xff0c;本框架无需用户安装电脑微信&#x…

vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法

1、先上个截图&#xff1a; 说明&#xff1a;拖动上面的分隔栏就可以实现&#xff0c;改变左右区域的大小。 2、上面的例子来自官网的&#xff1a; Container 布局容器 | Element Plus 3、拖动的效果来自&#xff1a; https://juejin.cn/post/7029640316999172104#heading-1…

Excel 无法打开文件

Excel 无法打开文件 ‘新建 Microsoft Excel 工作表.xlsx",因为 文件格式或文件扩展名无效。请确定文件未损坏&#xff0c;并且文件扩展名与文件的格式匹配。

K8S node节点没有相应的pod镜像运行故障处理办法

查看从节点状态 kubectl describe node k8s-node1以下是报错提示 解决办法 需要处理node1节点上的磁盘空间&#xff0c;磁盘空间需要在85%内 处理后的状态 处理正常

使用代理时Stable Diffusion无法正常下载各类模型的解决办法

最近发现了 Stable Diffusion 这个好玩的ai绘画工具&#xff0c;不得不感叹现在ai工具已经进化到这么简单易用的程度&#xff0c;只要下载对应的模型就可以生成各种有意思的图片 就算你没有编程基础&#xff0c;跟着教程也能弄出来 不过使用过程中发现部分功能无法使用 查看日…