1 为什么需要状态管理?
(1) 状态管理的作用

在编写一个应用的过程中,我们有大量的State需要来进行管理,而正是对这些State的改变,来更新界面的刷新:
(2) 状态管理 分类
1) 短时状态
某些状态只需要在自己的Widget中使用即可
比如:
- 我们之前做的简单计数器counter
- 一个PageView组件记录当前的页面
- 一个动画记录当前的进度
- 一个BottomNavigationBar中当前被选中的tab
这种状态我们只需要使用StatefulWidget对应的State类自己管理即可,Widget树中的其它部分并不需要访问这个状态。
2) 全局状态
开发中也有非常多的状态需要在多个部分进行共享
比如:
- 用户一个个性化选项
- 用户的登录状态信息
- 一个电商应用的购物车
- 一个新闻应用的已读消息或者未读消息
这种状态我们如果在Widget之间传递来、传递去,那么是无穷尽的,并且代码的耦合度会变得非常高,牵一发而动全身,无论是代码编写质量、后期维护、可扩展性都非常差。
这个时候我们可以选择全局状态管理的方式,来对状态进行统一的管理和应用。
2 全局状态管理
(1) InheritedWidget (不推荐)
InheritedWidget,可以实现跨组件数据的传递。
- of方法通过context开始去查找祖先的Widget
- updateShouldNotify方法是对比新旧Widget,是否需要对更新相关依赖的Widget ```dart import ‘package:flutter/material.dart’;
void main() { runApp(const MyApp()); }
class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: ‘Flutter Demo’, theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: ‘Flutter Demo Home Page’), ); } }
class CounterWidget extends InheritedWidget { final int counter; CounterWidget({required this.counter, required Widget child}) : super(child: child);
static CounterWidget of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); }
@override bool updateShouldNotify(InheritedWidget oldWidget) { // 如果返回为true, 执行state中的didChangeDependencies return counter != oldWidget.counter; } }
class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title;
@override
State
class _MyHomePageState extends State
class ShowData1 extends StatelessWidget { const ShowData1({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { int counter = CounterWidget.of(context).counter; return Card( color: Colors.blue, child: Text(“当前计数: $counter”), ); } }
class ShowData2 extends StatelessWidget { const ShowData2({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { int counter = CounterWidget.of(context).counter; return Container( child: Text(“当前计数: $counter”), ); } }
<a name="sYO48"></a>## (2) Provider (推荐)Provider底层依赖于InheritedWidget, 使得共享状态更方便<br />在pubspec中添加依赖:> provider: ^6.0.2```dartimport 'package:flutter/material.dart';// 1 创建需要共享的数据class CounterProvider extends ChangeNotifier {int _counter = 100;int get counter {return _counter;}set counter(int value) {_counter = value;notifyListeners();}}
import 'package:fltest/viewmodel/viewmodel.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';void main() {runApp(// 2 在Widget Tree中插入ChangeNotifierProviderChangeNotifierProvider(create: (ctx) => CounterProvider(),child: const MyApp(),));}class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key);// This widget is the root of your application.@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),home: const MyHomePage(title: 'Flutter Demo Home Page'),);}}class MyHomePage extends StatefulWidget {const MyHomePage({Key? key, required this.title}) : super(key: key);final String title;@overrideState<MyHomePage> createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(widget.title),),body: Container(alignment: Alignment.center,child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [ShowData1(),ShowData2(),],),),// 4 消费-写floatingActionButton: Consumer<CounterProvider>(builder: (context, value, child) => FloatingActionButton(child: child,onPressed: () {value.counter += 1;},),child: Icon(Icons.add), // 性能优化, 避免不必要的重新构建),);}}class ShowData1 extends StatelessWidget {const ShowData1({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {// 3 监听int counter = Provider.of<CounterProvider>(context).counter;return Container(color: Colors.blue,child: Text("当前计数: $counter"),);}}class ShowData2 extends StatelessWidget {const ShowData2({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return Container(color: Colors.red,// 5 消费-读child: Consumer<CounterProvider>(builder: (context, value, child) {return Text("当前计数: ${value.counter}");},),);}}
1) 使用Selector替换Consumer进行性能优化
作用:
- 对原有的数据进行格式转换 (前 -> 后)
- 选择是否重新构建builder返回的widget
floatingActionButton: Selector<CounterProvider, CounterProvider>(selector: (ctx, value) => value,shouldRebuild: (prev, next) => false,builder: (context, value, child) => FloatingActionButton(child: child,onPressed: () {value.counter += 1;},),child: Icon(Icons.add), // 性能优化, 避免不必要的重新构建),
(3) MultiProvider
runApp(MultiProvider(providers: [ChangeNotifierProvider(create: (ctx) => CounterProvider()),ChangeNotifierProvider(create: (ctx) => UserProvider()),],child: MyApp(),));
