在 Flutter 状态管理方案中,Bloc(Business Logic Component)依然是企业级项目最稳定、最规范的选择之一。随着版本演进(Bloc v8+),API 已经更加简洁、类型安全更强。
本文将带你从 0 到 1 掌握:
- Bloc & Cubit 核心原理
- 最新 API 用法(2026)
- 实战示例(登录 + 列表)
- Bloc vs Cubit 对比
- 与 GetX / Provider 区别
- 项目最佳实践
一、什么是 Bloc?
Bloc 是一种基于 事件驱动(Event-driven)+ 单向数据流(Unidirectional Data Flow) 的状态管理方案。
核心思想:
UI -> Event -> Bloc -> State -> UI
👉 UI 只负责发送事件
👉 Bloc 负责处理逻辑
👉 State 负责描述状态
二、Bloc vs Cubit(重点)
1️⃣ Cubit(推荐优先使用)
更轻量,没有 Event:
UI -> Cubit -> State
适合场景:
- 页面状态
- 表单
- 简单业务逻辑
示例代码:
dart
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
2️⃣ Bloc(复杂场景)
有 Event:
UI -> Event -> Bloc -> State
适合场景:
- 复杂业务流程
- 多状态转换
- 异步流复杂控制
三、最新版 Bloc 写法(重点)
Bloc v8+ 推荐使用 on 注册事件
1️⃣ 定义 Event
dart
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}
2️⃣ 定义 State
dart
class CounterState {
final int count;
CounterState(this.count);
}
3️⃣ Bloc 实现
dart
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState(0)) {
on<IncrementEvent>((event, emit) {
emit(CounterState(state.count + 1));
});
on<DecrementEvent>((event, emit) {
emit(CounterState(state.count - 1));
});
}
}
四、UI 层使用(核心)
1️⃣ 提供 Bloc
dart
BlocProvider(
create: (_) => CounterCubit(),
child: MyPage(),
)
2️⃣ 监听状态
dart
BlocBuilder<CounterCubit, int>(
builder: (context, count) {
return Text('$count');
},
)
3️⃣ 触发事件 / 方法
dart
context.read<CounterCubit>().increment();
五、完整实战:登录流程(推荐收藏🔥)
状态设计
dart
enum LoginStatus { initial, loading, success, error }
class LoginState {
final LoginStatus status;
final String? error;
LoginState({
this.status = LoginStatus.initial,
this.error,
});
LoginState copyWith({
LoginStatus? status,
String? error,
}) {
return LoginState(
status: status ?? this.status,
error: error,
);
}
}
Cubit 实现
dart
class LoginCubit extends Cubit<LoginState> {
LoginCubit() : super(LoginState());
Future<void> login(String username, String password) async {
emit(state.copyWith(status: LoginStatus.loading));
try {
await Future.delayed(Duration(seconds: 2));
if (username == "admin") {
emit(state.copyWith(status: LoginStatus.success));
} else {
throw Exception("账号错误");
}
} catch (e) {
emit(state.copyWith(
status: LoginStatus.error,
error: e.toString(),
));
}
}
}
UI 写法
dart
BlocConsumer<LoginCubit, LoginState>(
listener: (context, state) {
if (state.status == LoginStatus.success) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("登录成功")));
}
},
builder: (context, state) {
if (state.status == LoginStatus.loading) {
return CircularProgressIndicator();
}
return ElevatedButton(
onPressed: () {
context.read<LoginCubit>().login("admin", "123");
},
child: Text("登录"),
);
},
);
六、Bloc 常用组件总结
| 组件 | 作用 |
|---|---|
| BlocProvider | 提供 Bloc |
| BlocBuilder | 构建 UI |
| BlocListener | 监听副作用 |
| BlocConsumer | Builder + Listener |
| RepositoryProvider | 提供数据层 |
七、Bloc 最佳实践(非常重要)
✅ 1. 分层结构
推荐结构:
lib/
├── data/ // 数据层
├── repository/ // 仓库层
├── cubit / bloc/ // 状态管理层
├── view/ // 视图层
✅ 2. 状态不可变(immutable)
推荐使用:
- freezed
- equatable
dart
class CounterState extends Equatable {
final int count;
const CounterState(this.count);
@override
List<Object> get props => [count];
}
✅ 3. 避免在 UI 写逻辑
❌ 错误写法:
dart
onPressed: () {
if (xxx) ... // 逻辑直接写在UI中
}
✅ 正确写法:
dart
onPressed: () {
cubit.doSomething(); // 逻辑封装在Cubit/Bloc中
}
✅ 4. 使用 BlocObserver 调试
dart
class MyObserver extends BlocObserver {
@override
void onChange(BlocBase bloc, Change change) {
print(change);
super.onChange(bloc, change);
}
}
八、Bloc vs GetX vs Provider
| 特性 | Bloc | GetX | Provider |
|---|---|---|---|
| 学习成本 | 高 | 低 | 中 |
| 规范性 | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| 可维护性 | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| 企业级 | ✅ | ⚠️ | ✅ |
| 响应式 | 中 | 强 | 中 |
👉 总结:
- 小项目 → GetX
- 中项目 → Provider / Cubit
- 大项目 → Bloc(推荐)
九、Bloc 适合什么项目?
✅ 推荐使用场景:
- 中大型 Flutter 项目
- 多人协作
- 复杂业务(支付、IM、视频流)
- 需要高可维护性
十、总结
一句话总结:
👉 Cubit = 简化版 Bloc(80% 场景够用)
👉 Bloc = 复杂业务的终极方案
🎯 最终建议(2026)
- ✔ 优先用 Cubit
- ✔ 复杂逻辑再用 Bloc
- ✔ 配合 freezed + repository 才是完整体