flutter学习之状态管理相关组件

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);
});
});
}

十、选择建议

  1. 新手入门 :从 setStateProvider 开始
  2. 中小项目 :使用 ProviderGetX
  3. 大型项目 :考虑 BLoCRiverpod
  4. 快速开发GetX 是很好的选择
  5. 需要强类型 :选择 Riverpod
  6. 响应式编程爱好者 :尝试 MobX

记住:没有最好的状态管理方案,只有最适合你项目需求的方案。根据项目规模、团队经验和具体需求来选择。

相关推荐
问道飞鱼1 小时前
【大模型学习】LangChain 入门指南:基本概念、核心功能与简单示例
java·学习·langchain
ADHD多动联盟1 小时前
ADHD运动干预方案是什么?学习困难儿童的主要运动方式有哪些?
学习·学习方法·玩游戏
星幻元宇VR2 小时前
VR司法矫正宣教机|智慧法治教育新方式
科技·学习·安全·vr·虚拟现实
掘金安东尼2 小时前
⏰前端周刊第 456 期(v2026.3.15)
前端·javascript·面试
还是大剑师兰特2 小时前
Vue3 通用可复用动态插槽组件(终极版)
前端·javascript·vue.js
鄭郑2 小时前
STM32学习笔记--SPI初始化与数据收发(01)
笔记·stm32·学习
像素猎人2 小时前
以数据结构之——树来体会深度优先搜索【dfs】和广度优先搜索【bfs】的妙用:学比特算法课的自用笔记
数据结构·c++·学习·dfs·bfs·深度优先搜索
nibabaoo2 小时前
前端开发攻略---在 Vue 3 项目中使用 vue-i18n 实现国际化多语言
前端·javascript·国际化·i18n·vue3