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
```dart
import '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中插入ChangeNotifierProvider
ChangeNotifierProvider(
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.
@override
Widget 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;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget 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);
@override
Widget 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);
@override
Widget 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(),
));