本文用多个方案给出完整可落地的状态管理实现范式,并附上优缺点与使用场景,方便你根据项目复杂度做选择。
1. Provider:轻量、易上手
适合:中小项目、快速迭代
优点:简单、和 Flutter 生态深度兼容
缺点:依赖隐式、复杂业务容易膨胀
1.1 定义 State
class CounterState extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count += 1;
notifyListeners();
}
void reset() {
_count = 0;
notifyListeners();
}
}
1.2 注入 Provider
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterState()),
],
child: const MyApp(),
)
1.3 UI 订阅与渲染
class CounterPage extends StatelessWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Consumer<CounterState>(
builder: (_, state, __) => Text('${state.count}'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: context.read<CounterState>().increment,
child: const Icon(Icons.add),
),
);
}
}
1.4 异步状态(加载 + 错误)
class UserState extends ChangeNotifier {
bool loading = false;
String? error;
User? user;
Future<void> loadUser() async {
loading = true;
error = null;
notifyListeners();
try {
user = await api.fetchUser();
} catch (e) {
error = e.toString();
} finally {
loading = false;
notifyListeners();
}
}
}
1.5 使用场景
- 页面级状态、局部模块状态
- 简单业务逻辑与轻量协作团队
2. Riverpod:更强的可测试性
适合:中大型项目、依赖复杂、强调可测试性
优点:类型安全、无 BuildContext 依赖、测试友好
缺点:学习成本略高,概念更多
2.1 StateProvider(简单状态)
final counterProvider = StateProvider<int>((ref) => 0);
class CounterPage extends ConsumerWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Scaffold(
body: Center(child: Text('$count')),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: const Icon(Icons.add),
),
);
}
}
2.2 StateNotifier(复杂状态)
class UserState {
final bool loading;
final String? error;
final User? user;
const UserState({this.loading = false, this.error, this.user});
}
class UserNotifier extends StateNotifier<UserState> {
UserNotifier() : super(const UserState());
Future<void> loadUser() async {
state = const UserState(loading: true);
try {
final user = await api.fetchUser();
state = UserState(user: user);
} catch (e) {
state = UserState(error: e.toString());
}
}
}
final userProvider = StateNotifierProvider<UserNotifier, UserState>(
(ref) => UserNotifier(),
);
2.3 FutureProvider / StreamProvider
final userFutureProvider = FutureProvider<User>((ref) async {
return api.fetchUser();
});
class UserView extends ConsumerWidget {
const UserView({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncUser = ref.watch(userFutureProvider);
return asyncUser.when(
data: (u) => Text(u.name),
loading: () => const CircularProgressIndicator(),
error: (e, _) => Text(e.toString()),
);
}
}
2.4 Provider 组合与依赖
final apiProvider = Provider<ApiClient>((ref) => ApiClient());
final repoProvider = Provider<UserRepo>((ref) => UserRepo(ref.read(apiProvider)));
2.5 使用场景
- 依赖复杂、模块多、需要严格边界
- 强调可测试与可维护
3. BLoC:流程清晰、事件驱动
适合:复杂业务流程、多人协作
优点:事件-状态模型清晰、可追踪
缺点:样板代码多、学习成本高
3.1 基本结构
abstract class AuthEvent {}
class LoginPressed extends AuthEvent {
final String account;
final String pwd;
LoginPressed(this.account, this.pwd);
}
abstract class AuthState {}
class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {}
class AuthSuccess extends AuthState {}
class AuthError extends AuthState {
final String message;
AuthError(this.message);
}
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc() : super(AuthInitial()) {
on<LoginPressed>((event, emit) async {
emit(AuthLoading());
try {
await auth.login(event.account, event.pwd);
emit(AuthSuccess());
} catch (e) {
emit(AuthError(e.toString()));
}
});
}
}
3.2 BlocBuilder / BlocListener
BlocProvider(
create: (_) => AuthBloc(),
child: BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
if (state is AuthError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.message)),
);
}
},
child: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is AuthLoading) return const CircularProgressIndicator();
return ElevatedButton(
onPressed: () => context.read<AuthBloc>().add(LoginPressed('a', 'b')),
child: const Text('Login'),
);
},
),
),
);
3.3 使用场景
- 登录、支付、流程型业务
- 需要事件可追踪与严格状态转换
4. GetX:快速、但需约束
适合:快速开发、小团队
优点:上手快、语法简洁
缺点:全局依赖风险高、边界易模糊
4.1 基本示例
class CounterController extends GetxController {
var count = 0.obs;
void inc() => count.value++;
}
class CounterPage extends StatelessWidget {
final controller = Get.put(CounterController());
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Obx(() => Text('${controller.count.value}'))),
floatingActionButton: FloatingActionButton(
onPressed: controller.inc,
child: const Icon(Icons.add),
),
);
}
}
4.2 路由与依赖注入
GetMaterialApp(
getPages: [
GetPage(name: '/home', page: () => HomePage()),
],
);
class BindingsExample extends Bindings {
@override
void dependencies() {
Get.put(CounterController());
}
}
4.3 使用场景
- 迭代快、状态简单的应用
- 但需要明确全局依赖边界
5. Redux:可预测但样板多
适合:强约束、需要可追踪状态变更
优点:单向数据流清晰、调试友好
缺点:样板多、学习成本高
5.1 核心概念
class AppState {
final int count;
AppState(this.count);
}
class IncrementAction {}
AppState reducer(AppState state, dynamic action) {
if (action is IncrementAction) {
return AppState(state.count + 1);
}
return state;
}
5.2 Store 与 UI
final store = Store<AppState>(reducer, initialState: AppState(0));
StoreProvider(
store: store,
child: StoreConnector<AppState, int>(
converter: (store) => store.state.count,
builder: (_, count) => Text('$count'),
),
);
6. MobX:响应式但需规范
适合:偏响应式思维、业务状态多变
优点:写法简洁、响应式直观
缺点:需要 codegen,团队规范很重要
6.1 定义 Store
part 'counter.g.dart';
class Counter = _Counter with _$Counter;
abstract class _Counter with Store {
@observable
int count = 0;
@action
void increment() => count++;
}
6.2 UI 订阅
final counter = Counter();
Observer(
builder: (_) => Text('${counter.count}'),
);
7. 如何选型:按复杂度决策
- 简单页面 / 小项目:Provider / GetX
- 中大型项目:Riverpod
- 流程型业务/多人协作:BLoC
8. 状态划分建议
- 页面状态:局部 Provider
- 模块状态:模块入口注入
- 全局状态:App 根节点注入
总结
状态管理的核心不是框架,而是边界清晰与责任划分。先选对场景,再选合适的工具,才能长期稳定维护。