为什么需要状态管理
Flutter 的 Widget 树是单向数据流的。当状态只在单个 Widget 内部时,用 setState() 足够了。但当多个页面需要共享同一份数据时,逐层传递 props 会让代码变得混乱不堪——这就是状态管理要解决的问题。
Provider
Provider 是 Flutter 官方推荐的轻量级方案,基于 InheritedWidget 封装。核心思路是将状态对象注入 Widget 树,子孙节点通过 context.watch() 或 context.read() 订阅。
// 定义状态
class CounterNotifier extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 通知所有监听者重建
}
}
// 注入
ChangeNotifierProvider(
create: (_) => CounterNotifier(),
child: const MyApp(),
)
// 消费
Text('${context.watch<CounterNotifier>().count}')
优点:简单直观,上手快,官方文档完善。
缺点:依赖 BuildContext,测试时需要额外包裹 Widget 树;大型项目容易出现 Provider 嵌套地狱。
Riverpod
Riverpod 由 Provider 作者重新设计,彻底摆脱对 BuildContext 的依赖。所有 Provider 都是全局声明的顶级变量,编译期即可检测错误。
// 声明 Provider(全局,类型安全)
final counterProvider = StateNotifierProvider<CounterNotifier, int>(
(ref) => CounterNotifier(),
);
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}
// 在 Widget 中使用(ConsumerWidget)
class CounterPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('$count');
}
}
优点:类型安全,可组合,测试友好,支持异步状态(AsyncValue)。
缺点:概念较多(Provider / Notifier / AsyncNotifier),新手学习曲线稍陡。
BLoC
BLoC(Business Logic Component)是严格分层的架构模式,将 UI 事件(Event)映射到状态(State),通过流(Stream)驱动 UI 更新。
// Event
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
// State
class CounterState {
final int count;
const CounterState(this.count);
}
// BLoC
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(const CounterState(0)) {
on<IncrementEvent>((event, emit) {
emit(CounterState(state.count + 1));
});
}
}
优点:层次清晰,可测试性极高,适合大型团队协作。
缺点:样板代码多,简单功能也需要定义 Event/State 类,对小项目来说过重。
横向对比
| 维度 | Provider | Riverpod | BLoC |
|---|---|---|---|
| 上手难度 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 类型安全 | 一般 | 优秀 | 优秀 |
| 可测试性 | 一般 | 优秀 | 极佳 |
| 适用规模 | 小~中 | 中~大 | 大型团队 |
| 样板代码 | 少 | 中等 | 多 |
| 异步支持 | 需手动 | 内置 | 内置 |
我的选择
对于个人项目或小团队,我强烈推荐 Riverpod。它在简洁性和工程性之间取得了很好的平衡,Riverpod Generator(代码生成)出来后样板代码大幅减少,配合 AsyncValue 处理异步状态非常优雅。
如果你在面试或进入大公司团队,BLoC 是必须掌握的。它在可测试性和可追溯性上无可替代。