Flutter 状态管理全面指南
状态管理是 Flutter 开发中的核心概念,理解不同场景下的状态管理方案至关重要。
一、状态管理基础
1. StatefulWidget 基础状态管理
dart
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
void _increment() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('计数器: $_counter'),
ElevatedButton(
onPressed: _increment,
child: Text('增加'),
),
],
);
}
}
2. 状态提升 (Lifting State Up)
dart
// 父组件管理状态
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
void _increment() {
setState(() => _counter++);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
// 显示状态
DisplayWidget(counter: _counter),
// 修改状态
ControlWidget(onIncrement: _increment),
],
);
}
}
// 只负责显示的子组件
class DisplayWidget extends StatelessWidget {
final int counter;
DisplayWidget({required this.counter});
@override
Widget build(BuildContext context) {
return Text('计数器: $counter');
}
}
// 只负责控制的子组件
class ControlWidget extends StatelessWidget {
final VoidCallback onIncrement;
ControlWidget({required this.onIncrement});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onIncrement,
child: Text('增加'),
);
}
}
二、InheritedWidget 状态共享
1. 基础 InheritedWidget
dart
// 1. 创建 InheritedWidget
class CounterInheritedWidget extends InheritedWidget {
final int counter;
final VoidCallback increment;
CounterInheritedWidget({
required this.counter,
required this.increment,
required Widget child,
}) : super(child: child);
// 2. 定义静态方法方便子组件访问
static CounterInheritedWidget? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CounterInheritedWidget>();
}
// 3. 当数据变化时通知依赖的子组件
@override
bool updateShouldNotify(CounterInheritedWidget oldWidget) {
return counter != oldWidget.counter;
}
}
// 4. 使用 InheritedWidget
class InheritedExample extends StatefulWidget {
@override
_InheritedExampleState createState() => _InheritedExampleState();
}
class _InheritedExampleState extends State<InheritedExample> {
int _counter = 0;
void _increment() {
setState(() => _counter++);
}
@override
Widget build(BuildContext context) {
return CounterInheritedWidget(
counter: _counter,
increment: _increment,
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DisplayWidget(),
SizedBox(height: 20),
ControlWidget(),
],
),
),
),
);
}
}
// 5. 子组件访问共享状态
class DisplayWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = CounterInheritedWidget.of(context)?.counter ?? 0;
return Text('计数器: $counter');
}
}
class ControlWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final increment = CounterInheritedWidget.of(context)?.increment;
return ElevatedButton(
onPressed: increment,
child: Text('增加'),
);
}
}
三、Provider(官方推荐)
1. Provider 基础使用
yaml
# pubspec.yaml
dependencies:
provider: ^6.0.0
dart
// 1. 创建 Model
class CounterModel with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 通知监听者
}
void decrement() {
_count--;
notifyListeners();
}
}
// 2. 在顶层提供 Model
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterModel()),
// 可以添加更多 Provider
],
child: MyApp(),
),
);
}
// 3. 消费数据
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 方式1: 使用 Consumer
return Consumer<CounterModel>(
builder: (context, counter, child) {
return Text('计数器: ${counter.count}');
},
);
}
}
class CounterButtons extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 方式2: 使用 Provider.of
final counter = Provider.of<CounterModel>(context);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: counter.decrement,
child: Text('-'),
),
SizedBox(width: 20),
ElevatedButton(
onPressed: counter.increment,
child: Text('+'),
),
],
);
}
}
// 方式3: 使用 Selector(性能优化)
class OptimizedDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Selector<CounterModel, int>(
selector: (context, counter) => counter.count,
builder: (context, count, child) {
return Text('计数器: $count');
},
);
}
}
2. 多 Model 管理
dart
// 用户 Model
class UserModel with ChangeNotifier {
String _name = '张三';
int _age = 25;
String get name => _name;
int get age => _age;
void updateUser(String newName, int newAge) {
_name = newName;
_age = newAge;
notifyListeners();
}
}
// 主题 Model
class ThemeModel with ChangeNotifier {
bool _isDark = false;
bool get isDark => _isDark;
ThemeData get theme => _isDark ? ThemeData.dark() : ThemeData.light();
void toggleTheme() {
_isDark = !_isDark;
notifyListeners();
}
}
// 应用入口
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserModel()),
ChangeNotifierProvider(create: (_) => ThemeModel()),
ChangeNotifierProvider(create: (_) => CounterModel()),
],
child: MyApp(),
),
);
}
// 使用多个 Provider
class ProfilePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<UserModel>(context);
final theme = Provider.of<ThemeModel>(context);
return Scaffold(
appBar: AppBar(
title: Text('个人资料'),
backgroundColor: theme.isDark ? Colors.black : Colors.blue,
),
body: Center(
child: Column(
children: [
Text('姓名: ${user.name}'),
Text('年龄: ${user.age}'),
Switch(
value: theme.isDark,
onChanged: (_) => theme.toggleTheme(),
),
],
),
),
);
}
}
3. FutureProvider 和 StreamProvider
dart
// FutureProvider 示例
class DataService {
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return '加载的数据';
}
}
void main() {
runApp(
MultiProvider(
providers: [
Provider(create: (_) => DataService()),
FutureProvider<String>(
create: (context) => context.read<DataService>().fetchData(),
initialData: '正在加载...',
),
],
child: MyApp(),
),
);
}
class DataDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
final data = context.watch<String>();
return Center(
child: Text(data),
);
}
}
// StreamProvider 示例
class TimerService {
Stream<int> get timerStream => Stream.periodic(
Duration(seconds: 1),
(count) => count,
).take(10);
}
void main() {
runApp(
Provider(
create: (_) => TimerService(),
child: StreamProvider<int>(
create: (context) => context.read<TimerService>().timerStream,
initialData: 0,
child: MyApp(),
),
),
);
}
class TimerDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
final seconds = context.watch<int>();
return Center(
child: Text('已过去 $seconds 秒'),
);
}
}
四、Riverpod(Provider 的改进版)
1. Riverpod 基础
yaml
# pubspec.yaml
dependencies:
flutter_riverpod: ^2.0.0
dart
// 1. 创建 Provider
final counterProvider = StateProvider<int>((ref) => 0);
// 2. 使用 ConsumerWidget
class CounterApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('计数器: $count'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Text('增加'),
),
],
),
),
);
}
}
// 3. 使用 ConsumerStatefulWidget
class CounterPage extends ConsumerStatefulWidget {
@override
ConsumerState<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends ConsumerState<CounterPage> {
@override
Widget build(BuildContext context) {
final count = ref.watch(counterProvider);
return Scaffold(
body: Center(
child: Text('计数器: $count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
ref.read(counterProvider.notifier).state++;
},
child: Icon(Icons.add),
),
);
}
}
2. Riverpod 进阶用法
dart
// 异步 Provider
final userProvider = FutureProvider<String>((ref) async {
await Future.delayed(Duration(seconds: 2));
return '张三';
});
// 组合 Provider
final authProvider = Provider<AuthService>((ref) => AuthService());
final userInfoProvider = FutureProvider<User>((ref) async {
final auth = ref.watch(authProvider);
return await auth.getCurrentUser();
});
// 状态通知 Provider
final counterNotifierProvider = StateNotifierProvider<CounterNotifier, int>(
(ref) => CounterNotifier(),
);
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
}
// 使用
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterNotifierProvider);
final notifier = ref.read(counterNotifierProvider.notifier);
return Column(
children: [
Text('计数器: $count'),
ElevatedButton(
onPressed: notifier.increment,
child: Text('增加'),
),
],
);
}
}
五、GetX(轻量高效)
1. GetX 基础使用
yaml
# pubspec.yaml
dependencies:
get: ^4.6.0
dart
// 1. 创建 Controller
class CounterController extends GetxController {
var count = 0.obs; // 响应式变量
void increment() => count.value++;
void decrement() => count.value--;
}
// 2. 使用 GetView(推荐)
class CounterPage extends GetView<CounterController> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Obx(() => Text('计数器: ${controller.count}')),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.increment,
child: Icon(Icons.add),
),
);
}
}
// 3. 绑定 Controller
void main() {
runApp(GetMaterialApp(
home: CounterPage(),
initialBinding: BindingsBuilder(() {
Get.put(CounterController());
}),
));
}
// 或者使用 GetBuilder
class CounterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<CounterController>(
init: CounterController(),
builder: (controller) {
return Column(
children: [
Text('计数器: ${controller.count}'),
ElevatedButton(
onPressed: controller.increment,
child: Text('增加'),
),
],
);
},
);
}
}
2. GetX 路由和依赖注入
dart
// 1. 路由管理
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('首页')),
body: Center(
child: ElevatedButton(
child: Text('跳转到详情'),
onPressed: () {
Get.to(
() => DetailPage(),
arguments: {'id': 123},
transition: Transition.rightToLeft,
duration: Duration(milliseconds: 300),
);
},
),
),
);
}
}
// 2. 详情页获取参数
class DetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final args = Get.arguments;
return Scaffold(
appBar: AppBar(title: Text('详情页')),
body: Center(child: Text('ID: ${args['id']}')),
);
}
}
// 3. 依赖注入
class ApiService {
Future<String> fetchData() async => '数据';
}
class HomeController extends GetxController {
final ApiService apiService = Get.find();
var data = ''.obs;
@override
void onInit() {
super.onInit();
loadData();
}
void loadData() async {
data.value = await apiService.fetchData();
}
}
// 4. 全局绑定
void main() {
runApp(GetMaterialApp(
initialBinding: AppBindings(),
home: HomePage(),
));
}
class AppBindings extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => ApiService(), fenix: true);
Get.lazyPut(() => HomeController());
}
}
六、BLoC/Cubit
1. Cubit 基础
yaml
# pubspec.yaml
dependencies:
flutter_bloc: ^8.0.0
dart
// 1. 创建 Cubit
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
// 2. 提供 Cubit
void main() {
runApp(
BlocProvider(
create: (context) => CounterCubit(),
child: MyApp(),
),
);
}
// 3. 使用 BlocBuilder
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: BlocBuilder<CounterCubit, int>(
builder: (context, count) {
return Text('计数器: $count');
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<CounterCubit>().increment(),
child: Icon(Icons.add),
),
);
}
}
// 4. 使用 BlocConsumer
class CounterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocConsumer<CounterCubit, int>(
listener: (context, state) {
// 状态变化时执行
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('计数器变为: $state')),
);
},
builder: (context, state) {
return Column(
children: [
Text('计数器: $state'),
ElevatedButton(
onPressed: () => context.read<CounterCubit>().increment(),
child: Text('增加'),
),
],
);
},
);
}
}
2. BLoC 完整示例
dart
// 1. 定义事件
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}
// 2. 创建 BLoC
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<IncrementEvent>((event, emit) => emit(state + 1));
on<DecrementEvent>((event, emit) => emit(state - 1));
}
}
// 3. 使用
class BlocCounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CounterBloc(),
child: Scaffold(
body: Center(
child: BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text('计数器: $count');
},
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
child: Icon(Icons.add),
),
SizedBox(height: 10),
FloatingActionButton(
onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),
child: Icon(Icons.remove),
),
],
),
),
);
}
}
七、MobX
1. MobX 基础
yaml
# pubspec.yaml
dependencies:
mobx: ^2.0.0
flutter_mobx: ^2.0.0
dev_dependencies:
build_runner: ^2.0.0
mobx_codegen: ^2.0.0
dart
// counter_store.dart
import 'package:mobx/mobx.dart';
part 'counter_store.g.dart';
class CounterStore = _CounterStore with _$CounterStore;
abstract class _CounterStore with Store {
@observable
int count = 0;
@action
void increment() {
count++;
}
@action
void decrement() {
count--;
}
@computed
bool get isEven => count % 2 == 0;
}
// 运行命令生成代码
// flutter pub run build_runner build
// 使用
class CounterPage extends StatelessWidget {
final CounterStore store = CounterStore();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Observer(
builder: (_) => Text('计数器: ${store.count}'),
),
Observer(
builder: (_) => Text(store.isEven ? '偶数' : '奇数'),
),
ElevatedButton(
onPressed: store.increment,
child: Text('增加'),
),
],
),
),
);
}
}
八、状态管理方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| setState | 简单易用,无额外依赖 | 不适合复杂状态,性能较差 | 简单组件,局部状态 |
| Provider | 官方推荐,学习曲线平缓 | 需要手动管理依赖 | 中小型应用,团队协作 |
| Riverpod | Provider 改进版,编译安全 | 相对较新,社区较小 | 需要类型安全的中大型应用 |
| GetX | 功能全面,开发效率高 | 框架耦合度较高 | 快速开发,个人项目 |
| BLoC | 分离业务逻辑,可测试性强 | 样板代码较多 | 企业级应用,复杂业务逻辑 |
| MobX | 响应式,代码简洁 | 需要代码生成 | 熟悉响应式编程的团队 |
九、最佳实践
1. 状态分层
dart
// 1. 本地状态(使用 setState)
class LocalStateWidget extends StatefulWidget {
@override
_LocalStateWidgetState createState() => _LocalStateWidgetState();
}
// 2. 应用状态(使用 Provider/GetX/BLoC)
class AppState {
final UserModel user;
final SettingsModel settings;
final CartModel cart;
AppState({
required this.user,
required this.settings,
required this.cart,
});
}
// 3. 服务层(处理网络请求等)
class ApiService {
Future<User> fetchUser() async {
// 网络请求
}
}
2. 性能优化
dart
// 使用 const 构造函数
class MyWidget extends StatelessWidget {
const MyWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Text('Hello');
}
}
// 使用 ValueKey
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(items[index].id), // 使用唯一标识
title: Text(items[index].name),
);
},
);
// 使用 AutomaticKeepAliveClientMixin
class KeepAlivePage extends StatefulWidget {
@override
_KeepAlivePageState createState() => _KeepAlivePageState();
}
class _KeepAlivePageState extends State<KeepAlivePage>
with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; // 保持状态
@override
Widget build(BuildContext context) {
super.build(context);
return Container();
}
}
3. 测试状态管理
dart
// 测试 CounterCubit
void main() {
group('CounterCubit', () {
late CounterCubit counterCubit;
setUp(() {
counterCubit = CounterCubit();
});
tearDown(() {
counterCubit.close();
});
test('初始状态为0', () {
expect(counterCubit.state, 0);
});
test('增加操作', () {
counterCubit.increment();
expect(counterCubit.state, 1);
});
});
}
十、选择建议
- 新手入门 :从
setState和Provider开始 - 中小项目 :使用
Provider或GetX - 大型项目 :考虑
BLoC或Riverpod - 快速开发 :
GetX是很好的选择 - 需要强类型 :选择
Riverpod - 响应式编程爱好者 :尝试
MobX
记住:没有最好的状态管理方案,只有最适合你项目需求的方案。根据项目规模、团队经验和具体需求来选择。