前言:
主流的状态管理,一般用这几个管理组件,可以看看学学,当然,vibecoding时,要做好限制工作,不然会发疯的,最近国产模型,我个人感觉deepseek体感效果最好,比花了大价钱营销推广自己多牛的kimi、GLM明显强上一个档次,当然,仅限于这个时间段的国内模型。
一、总览
本讲的核心目标是帮助你理解 Flutter 中状态管理的本质,掌握从基础到主流的各类状态管理方案(Provider/ChangeNotifier、Riverpod、Bloc/Cubit),并学会根据实际场景划分全局状态和局部状态,最终能够在项目中选择最合适的状态管理方案并落地实现。
状态管理的核心痛点:Flutter 中 Widget 状态分散在各个组件中,跨组件/跨页面共享状态时会出现代码耦合、数据流向混乱、维护成本高的问题。本章节通过系统化讲解主流方案,解决「状态该存在哪、该如何传递、该如何更新」的核心问题。
所有状态管理方案都基于「单一数据源 + 观察者模式」,底层依赖 InheritedWidget(Provider/Riverpod)或 Stream(Bloc)实现状态传递和更新;
方案选择:
- 简单场景/快速开发:Provider/ChangeNotifier;
- 无上下文依赖/类型安全:Riverpod;
- 复杂业务/可测试性:Bloc/Cubit;
作用域划分:全局状态在 App 根节点初始化,局部状态在页面/组件层级初始化,最小化状态作用域可减少性能损耗。
最佳实践
-
优先使用「局部状态」,仅必要数据设为全局;
-
Riverpod 是 Provider 的升级版,新项目建议优先选择;
-
Bloc 适合团队协作/复杂业务,Cubit 适合简单业务;
-
避免过度封装,状态管理的核心是「清晰的数据流向」而非「炫技」。
- 核心模式:所有状态管理方案都遵循「单一数据源 + 观察者模式」,区别仅在于「通知方式」和「代码组织形式」。
- InheritedWidget:Provider/Riverpod 的底层基础,实现跨 Widget 树传递数据(无需手动层层传递)。
- 事件驱动:Bloc 的核心,将「状态修改动作」和「状态本身」解耦,通过 Event → State 的单向流管理状态。
- 作用域划分:全局状态(如用户登录信息)需在 App 根节点初始化,局部状态(如购物车弹窗状态)仅在对应页面层级初始化。
二、各方案详解
2.1 基础方案:Provider + ChangeNotifier
Provider + ChangeNotifier 是 Flutter 中最常用的状态管理组合方案。它们共同解决了一个核心问题:如何让多个 Widget 共享和响应数据变化。
核心属性/类
| 类/属性 | 作用 |
|---|---|
ChangeNotifier | 状态基类,通过 notifyListeners() 通知监听者状态变更 |
ChangeNotifierProvider | 提供状态的 Widget,子组件可获取状态 |
Consumer | 监听状态变更并重建 UI 的 Widget |
Provider.of<T>() | 直接获取状态(需指定 listen: true/false) |
基础案例(计数器)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// 1. 定义状态管理类
class CounterNotifier extends ChangeNotifier {
int _count = 0;
int get count => _count;
// 状态修改方法
void increment() {
_count++;
notifyListeners(); // 通知UI更新
}
void decrement() {
_count--;
notifyListeners();
}
}
// 2. 使用 Provider 包裹页面
class ProviderCounterPage extends StatelessWidget {
const ProviderCounterPage({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => CounterNotifier(), // 创建状态实例
child: Scaffold(
appBar: AppBar(title: Text("Provider 计数器")),
body: Center(
child: Consumer<CounterNotifier>( // 监听状态变更
builder: (context, counter, child) {
return Text(
"当前计数:${counter.count}",
style: TextStyle(fontSize: 24),
);
},
),
),
floatingActionButton: Builder(
builder: (context) {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () {
Provider.of<CounterNotifier>(context, listen: false).decrement();
},
child: Icon(Icons.remove),
),
SizedBox(width: 10),
FloatingActionButton(
onPressed: () {
Provider.of<CounterNotifier>(context, listen: false).increment();
},
child: Icon(Icons.add),
),
],
);
},
),
),
);
}
}
// 7. 入口函数
void main() {
runApp(MaterialApp(
title: "Provider 计数器",
home: ProviderCounterPage(),
));
}
注意事项
notifyListeners()必须在状态修改后调用,否则 UI 不会更新Provider.of<T>(context, listen: false)用于修改状态(不监听),listen: true用于监听状态(会重建 Widget),要注意context需要是监听组件的context,别引用错了造成监听失效- 局部状态建议用
Consumer缩小重建范围,避免整个页面重建; - 全局状态需在
MaterialApp外层初始化(如MultiProvider)。
2.2 主流方案1:Riverpod(Provider 升级版)
Riverpod 是 Provider 的改进版本,由同一作者开发,解决了 Provider 的诸多痛点,是目前 Flutter 社区最受欢迎的状态管理方案之一。
核心属性/类
| 类/属性 | 作用 |
|---|---|
Provider | 只读状态提供者(不可变数据) |
StateProvider | 可读写状态提供者(简单状态) |
NotifierProvider | 复杂状态提供者(对应自定义 Notifier) |
ref | 核心对象,用于读取/监听/修改状态 |
Consumer/ref.watch() | 监听状态变更 |
基础案例(计数器)
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod/legacy.dart';
// 1. 定义状态(全局/局部均可)
final counterProvider = StateProvider<int>((ref) => 0);
// 2. Riverpod 页面(需用 ProviderScope 包裹 App)
class RiverpodCounterPage extends ConsumerWidget {
const RiverpodCounterPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// 监听状态
final count = ref.watch(counterProvider);
return Scaffold(
appBar: AppBar(title: Text("Riverpod 计数器")),
body: Center(
child: Text(
"当前计数:$count",
style: TextStyle(fontSize: 24),
),
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () {
// 修改状态
ref.read(counterProvider.notifier).state--;
},
child: Icon(Icons.remove),
),
SizedBox(width: 10),
FloatingActionButton(
onPressed: () {
ref.read(counterProvider.notifier).state++;
},
child: Icon(Icons.add),
),
],
),
);
}
}
// App 入口需包裹 ProviderScope
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget{
const MyApp({super.key});
@override
Widget build(BuildContext context){
return MaterialApp(
home: RiverpodCounterPage()
);
}
}
注意事项
- 必须用
ProviderScope包裹整个 App(全局状态)或某个页面(局部状态); ref.watch()只能在build方法中使用,异步场景用ref.listen();- 复杂状态建议用
NotifierProvider+ 自定义Notifier类; - 无上下文依赖,可在任意地方(如工具类)读取/修改状态。
2.3 主流方案2:Bloc/Cubit
核心属性/类
| 类/属性 | 作用 |
|---|---|
Cubit | 简化版 Bloc,仅管理状态(无 Event 概念) |
Bloc | 完整版,通过 Event → State 单向流管理 |
BlocBuilder | 监听状态变更并重建 UI |
BlocProvider | 提供 Bloc/Cubit 实例 |
emit() | 发送新状态(Cubit/Bloc 核心方法) |
基础案例(计数器,Cubit 版)
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
// 1. 定义 Cubit 和状态
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0); // 初始状态
// 状态修改方法
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
// 2. Bloc 页面
class BlocCounterPage extends StatelessWidget {
const BlocCounterPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Bloc/Cubit 计数器")),
body: Center(
child: BlocBuilder<CounterCubit, int>( // 监听状态
builder: (context, count) {
return Text(
"当前计数:$count",
style: TextStyle(fontSize: 24),
);
},
),
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () {
// 获取 Cubit 并修改状态
context.read<CounterCubit>().decrement();
},
child: Icon(Icons.remove),
),
SizedBox(width: 10),
FloatingActionButton(
onPressed: () {
context.read<CounterCubit>().increment();
},
child: Icon(Icons.add),
),
],
),
);
}
}
// App 入口需包裹 ProviderScope
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget{
const MyApp({super.key});
@override
Widget build(BuildContext context){
return BlocProvider(
create: (context) => CounterCubit(),
child: MaterialApp(
home: BlocCounterPage()
),
);
}
}
注意事项
- Cubit 适合简单状态,Bloc 适合复杂业务(需区分 Event 和 State);
- 需在
dispose时关闭 Cubit/Bloc(BlocProvider 会自动处理); - 可通过
BlocListener监听状态变更并执行副作用(如弹窗、路由跳转); - 全局 Bloc 需在 App 根节点初始化(
MultiBlocProvider)。
2.4 全局/局部状态划分
| 类型 | 适用场景 | 实现方式 | 示例 |
|---|---|---|---|
| 全局状态 | 全 App 共享,如用户信息、主题、语言 | 在 MaterialApp 外层初始化状态管理器 | Provider/Riverpod/Bloc 包裹 MyApp |
| 局部状态 | 单页面/组件共享,如表单状态、弹窗状态 | 在页面/组件层级初始化状态管理器 | 仅在某个 Page 内包裹 Provider/Bloc |
示例:全局状态(用户信息)
// 全局用户状态(Provider 版)
class UserNotifier extends ChangeNotifier {
String _username = "未登录";
String get username => _username;
void login(String name) {
_username = name;
notifyListeners();
}
}
// App 入口初始化全局状态
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => UserNotifier(), // 全局状态
child: MaterialApp(
home: ProviderCounterPage(),
),
);
}
}