
状态管理是任何 Flutter 应用的骨干。它决定数据如何在应用内流动、组件之间如何通信,并最终决定代码库在不断增长时的可维护性。
面对如此多的选择——Provider、Bloc、Riverpod、GetX、MobX——挑选合适的方案可能让人无从下手。本指南将逐一拆解每种方案,并配以实际示例,帮助你做出明智的决定。
PROVIDER:官方推荐之选
Provider 是 Google 推荐的状态管理方案。它构建于 InheritedWidget 之上,提供简单且可扩展的解决方案,适合绝大多数应用。
// Counter model
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// Setup Provider
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
)
// Consume in UI
Consumer<CounterModel>(
builder: (context, counter, child) {
return Text('Count: ${counter.count}');
},
)优点
- Google 官方推荐
- 简单易学
- 文档完善
- 非常适合中小型应用
缺点
- 在大型应用中容易变得混乱
- 没有内置的异步处理
- 缺乏测试工具
- 样板代码冗长
BLOC:可预测、易测试
Bloc(Business Logic Component)遵循响应式编程范式。它将展示层与业务逻辑分离,让应用高度可测试、行为可预测。
// Events
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
// States
abstract class CounterState {}
class CounterInitial extends CounterState {}
class CounterValue extends CounterState {
final int count;
CounterValue(this.count);
}
// Bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterInitial()) {
on<Increment>((event, emit) {
emit(CounterValue(currentCount + 1));
});
}
}
// Usage
BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
if (state is CounterValue) {
return Text('Count: ${state.count}');
}
return Text('Count: 0');
},
)优点
- 高度可测试
- 状态变化可预测
- 非常适合复杂应用
- 出色的 DevTools 支持
缺点
- 学习曲线陡峭
- 样板代码繁多
- 对简单应用而言过于复杂
- 需要理解 Stream 的概念
RIVERPOD:PROVIDER 2.0
Riverpod 出自 Provider 原作者之手,修复了 Provider 的许多限制,同时保持简洁。它具备编译期安全,且不依赖 BuildContext。
// Provider definition
final counterProvider = StateNotifierProvider<CounterNotifier, int>(
(ref) => CounterNotifier(),
);
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
}
// Usage
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Column(
children: [
Text('Count: $count'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: Text('Increment'),
),
],
);
}
}优点
- 编译期安全
- 不依赖 BuildContext
- 内置缓存机制
- 出色的开发体验
缺点
- 较新,社区规模较小
- 版本更新时可能有破坏性改动
- 部分概念较为复杂
- 从 Provider 迁移需要花些功夫
GETX:一站式全能方案
GetX 不只是状态管理——它还内置路由、依赖注入及国际化功能,以极少的样板代码和高性能著称。
// Controller
class CounterController extends GetxController {
var count = 0.obs;
void increment() => count++;
void decrement() => count--;
}
// Usage
class CounterWidget extends StatelessWidget {
final CounterController controller = Get.put(CounterController());
@override
Widget build(BuildContext context) {
return Column(
children: [
Obx(() => Text('Count: ${controller.count}')),
ElevatedButton(
onPressed: controller.increment,
child: Text('Increment'),
),
],
);
}
}优点
- 样板代码极少
- 性能出色
- 一站式解决方案
- 容易上手
缺点
- 并非 Google 官方推荐
- “魔法”行为可能难以捉摸
- 与 GetX 生态系统紧密耦合
- 可预测性不及其他方案
你应该选择哪一个?
初学者之选
从 Provider 开始。它获官方推荐、文档完善,学习曲线平缓。
适合:学习 Flutter、中小型应用、原型开发
大型应用
业务逻辑复杂、对可测试性要求高时,使用 Bloc。样板代码的投入会在可维护性上得到回报。
适合:企业级应用、复杂状态、团队开发
现代应用
试试 Riverpod,享受最佳开发体验与编译期安全。它是 Flutter 状态管理的未来。
适合:全新项目、重视开发体验的团队、大量异步操作的应用
快速开发
需要快速开发、又不介意一点“魔法”时,选择 GetX。非常适合 MVP 和独立开发。
适合:MVP、个人项目、快速原型开发
状态管理最佳实践
尽量将状态放在最接近使用它的地方。不要把所有东西都放进全局状态。
将 UI 状态与业务逻辑分离。加载状态属于 UI,业务数据属于服务层。
尽可能让状态保持不可变。这样可以减少 bug,让调试更轻松。
为状态逻辑编写测试。状态管理属于业务逻辑,理应得到充分测试。
不要过度设计。选择能满足当前需求的最简单方案,日后随时可以重构。


