BLoC 从 0 到 1:先理解“状态机”,再谈 Flutter

很多人学 BLoC,是从 BlocProvider / BlocBuilder 开始的。

但真正决定你能不能用好 BLoC 的,从来不是这些 API,

而是:你有没有把系统当成一个状态机来看。

一、为什么会有 BLoC?

在最原始的 Flutter / Android 开发中,我们通常这样改状态:

Dart 复制代码
setState(() {
  loading = true;
  data = ...
  error = null;
});

这在小项目里没问题,但项目一复杂,三个问题必然出现:

❌ 1. 状态散落

loading / error / empty / submitting / success 混在页面里。

❌ 2. 变化不可控

谁在什么时候改了什么,只能靠人脑跟。

❌ 3. 流程无法建模

登录流、支付流、设备控制流,本质是状态机,代码却是变量拼凑。

本质问题只有一句话:

👉 系统没有"状态模型",只有"状态变量"。

二、BLoC 想解决的根问题

BLoC 的目标不是"把状态挪个地方放",

而是:

👉 把"状态变化本身"提升为系统的一等公民。

也就是说,系统必须明确三件事:

  • 系统有哪些状态(State)

  • 系统会收到哪些事件(Event)

  • 在不同状态下,收到事件会如何演进

这在系统层面叫一个词:

👉 状态机(State Machine)

三、BLoC 的最小世界观(脱离 Flutter)

在任何 BLoC 系统中,只有三个角色:

Dart 复制代码
Event:发生了什么
State:系统现在处于什么阶段
Bloc :状态机(决定如何迁移)

👉 系统的所有变化,必须经过:

Dart 复制代码
(Event + 当前 State) -> 新 State

这就是 BLoC 的全部本质。

四、从 0 手搓一个"迷你 BLoC"

先完全不看 flutter_bloc,我们用最原始方式写一个 BLoC。

1️⃣ 定义 State(系统阶段)

Dart 复制代码
abstract class CounterState {}

class Idle extends CounterState {}

class Counting extends CounterState {
  final int value;
  Counting(this.value);
}

注意:

这里不是"数据类",而是在描述:

👉 系统有哪些合法阶段

2️⃣ 定义 Event(系统输入)

Dart 复制代码
abstract class CounterEvent {}

class Increment extends CounterEvent {}

class Reset extends CounterEvent {}

Event 不是"函数",

Event 是:

👉 系统允许的变化来源。

3️⃣ 定义 Bloc(状态机核心)

Dart 复制代码
class CounterBloc {
  CounterState state = Idle();

  final _controller = StreamController<CounterState>.broadcast();
  Stream<CounterState> get stream => _controller.stream;

  void add(CounterEvent event) {
    if (state is Idle && event is Increment) {
      state = Counting(1);
    } 
    else if (state is Counting && event is Increment) {
      final v = (state as Counting).value + 1;
      state = Counting(v);
    } 
    else if (event is Reset) {
      state = Idle();
    }

    _controller.add(state);
  }
}

你现在已经拥有了一个完整 BLoC:

  • 只有 Event 能触发变化
  • 只有 Bloc 能修改 State
  • 所有变化路径都集中在一个地方

👉 这已经是一个状态机系统

五、你已经完成了关键转变

从这一刻开始:

❌ UI 不能直接改状态

❌ 业务不能随便改变量

只能:

bloc.add(Event)

👉 系统从"变量驱动",升级为:

👉 状态迁移驱动

六、为什么这一步在复杂系统里极其重要?

因为现在系统变成了:

Dart 复制代码
有限状态 + 有限事件 + 明确迁移

带来的直接能力是:

  • ✅ 所有状态可枚举

  • ✅ 所有入口可枚举

  • ✅ 所有路径可推理

  • ✅ 所有流程可测试

  • ✅ 所有异常分支可约束

这类系统最怕的不是"写得慢",

而是:

👉 状态乱跳、流程不可控、问题不可复现。

而 BLoC 正是为此而生。

个人理解: event 触发,一个入口,修改状态。

七、再把 Flutter 接进来(只是外壳)

flutter_bloc 只是把刚才这套机制:

  • 封装成类 Bloc
  • 帮你管理 Stream
  • 帮你绑定 Widget 生命周期

例如:

Dart 复制代码
BlocBuilder<CounterBloc, CounterState>(
  builder: (context, state) {
    if (state is Idle) return Text("0");
    if (state is Counting) return Text("${state.value}");
    return SizedBox();
  },
)

context.read<CounterBloc>().add(Increment());

框架只是"接 UI",
状态机模型完全没变。

八、如何用 BLoC 正确建模真实业务

一个真实业务 BLoC,通常不是"一个 int",而是:

👉 一个流程系统

例如"列表页面":

State 可能是:

  • Initial

  • Loading

  • Refreshing

  • Data

  • Empty

  • Error

  • NoMore

Event 可能是:

  • Load

  • Refresh

  • LoadMore

  • Retry

Bloc 做的事就是:

明确写出:在什么状态下,收到什么事件,系统走向什么新状态。

这一步是系统设计,而不是写 UI。

九、BLoC 在架构坐标系中的真实定位

从系统角度看:

  • Riverpod 擅长:结构系统(依赖 / 生命周期 / 自动传播)
  • BLoC 擅长:行为系统(流程 / 状态演进 / 约束)

BLoC 更接近:

  • Redux / MVI
  • 后端事件驱动系统
  • 协议状态机
  • 设备控制系统

它解决的不是"状态放哪",

而是:

👉 系统如何演进。

十、什么时候该优先考虑 BLoC?

当你的问题主要是:

  • 状态阶段多
  • 流程复杂
  • 异常分支多
  • 行为必须可预测
  • 系统必须可回放/可审计

👉 BLoC 非常合适。

当你的问题主要是:

  • 依赖复杂
  • 资源生命周期复杂
  • 数据自动联动
  • 组合关系多

👉 更偏 Riverpod 路线。

十一、总结一句话(这篇文章的核心)

BLoC 不是"Flutter 写法",

BLoC 是一种显式状态机架构

它把"状态变化",从代码细节,提升为系统模型。

相关推荐
恋猫de小郭2 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
恋猫de小郭17 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
明君879971 天前
Flutter 如何给图片添加多行文字水印
前端·flutter
四眼肥鱼1 天前
flutter 利用flutter_libserialport 实现SQ800 串口通信
前端·flutter
火柴就是我2 天前
让我们实现一个更好看的内部阴影按钮
android·flutter
王晓枫2 天前
flutter接入三方库运行报错:Error running pod install
前端·flutter
shankss2 天前
Flutter 下拉刷新库 pull_to_refresh_plus 设计与实现分析
flutter
忆江南3 天前
iOS 深度解析
flutter·ios
明君879973 天前
Flutter 实现 AI 聊天页面 —— 记一次 Markdown 数学公式显示的踩坑之旅
前端·flutter
恋猫de小郭3 天前
移动端开发稳了?AI 目前还无法取代客户端开发,小红书的论文告诉你数据
前端·flutter·ai编程