Flutter 的状态管理
如果你是从一个命令式的框架(如 Android SDK
或 iOS UIKit
)来到 Flutter
,你需要从一个新的角度思考应用开发的问题。
例如,在 Flutter
中,当你修改用户界面的某一个部分时,你不是直接修改它,而是重新构建这部分的用户界面。
Flutter
是一个声明式的框架。这意味着 Flutter
是通过构建其用户界面来反映当前应用程序的状态。
公式如下:
UI = f(state)
// UI: 表示用户界面
// f: 你的 build 方法
// state: 应用程序的当前状态
短暂状态(ephemeral state)和应用状态(app state)
状态(state)是指你用来构建用户界面的数据。它包含两种:
短暂状态
(ephemeral state)和应用状态
(app state)。
短暂状态(ephemeral state)
短暂状态
(有时称为 UI状态
或 本地状态
)一般是指单个小组件(Widget)内部的状态。
比如:
- 一个
PageView
中的当前页面_currentPage
- 一个复杂动画的当前进度
_progress
- 底部导航条(
BottomNavigationBar
)中的当前选中标签栏_selectedTab
非当前组件的其它组件很少需要访问这个状态。同时没有必要对它进行序列化存储。
换句话说,没有必要在这种状态上使用状态管理技术(ScopedModel
, Redux
等等)。你所需要的只是一个 StatefulWidget
。
应用状态(app state)
如果你的应用程序中的某个状态想要被许多组件共享,那么这个就是应用状态
(app state)。
比如:
- 用户偏好设置
- 登录信息
- 社交网络应用中的通知
- 电子商务应用中的购物车
- 新闻应用中文章的阅读/未读状态
应用状态管理
我们这里说的,Flutter 状态管理是指对应用状态
的管理。(因为对于短暂状态
来说,直接使用 StatefulWidget
就可以了。)
应用状态管理方法有很多。如何选择合理的应用状态管理方案,需要考虑你的应用程序的大小和复杂性,以及你的团队经验。
Flutter 官方推荐的方式是:Provider + ChangeNotifier,这也是最简单的方式,大部分情况下就能满足你的需求。
Provider
Provider 中你需要理解三个概念:
- ChangeNotifier
- ChangeNotifierProvider
- Consumer
ChangeNotifier
ChangeNotifier
是 Flutter SDK
中的一个简单的类,它为其监听器提供变化通知。换句话说,如果某个东西是一个 ChangeNotifier
,你就可以订阅它的变化。
在 provider
中,我们使用 ChangeNotifier
来封装你的应用状态
。
class CartModel extends ChangeNotifier {
/// Internal, private state of the cart.
final List<Item> _items = [];
/// An unmodifiable view of the items in the cart.
UnmodifiableListView<Item> get items => UnmodifiableListView(_items);
/// The current total price of all items (assuming all items cost $42).
int get totalPrice => _items.length * 42;
/// Adds [item] to cart. This and [removeAll] are the only ways to modify the
/// cart from the outside.
void add(Item item) {
_items.add(item);
// This call tells the widgets that are listening to this model to rebuild.
notifyListeners();
}
/// Removes all items from the cart.
void removeAll() {
_items.clear();
// This call tells the widgets that are listening to this model to rebuild.
notifyListeners();
}
}
ChangeNotifierProvider
ChangeNotifierProvider
是为其子组件提供 ChangeNotifier
实例的组件。它来自于 provider
。
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CartModel(),
child: const MyApp(),
),
);
}
Consumer
Consumer
是用来订阅 ChangeNotifier
的组件。
return Consumer<CartModel>(
builder: (context, cart, child) {
return Text("Total price: ${cart.totalPrice}");
},
);
Provider.of
如果你不想订阅 ChangeNotifier
,只想访问它。这时候你就可以使用 Provider.of
。
Provider.of<CartModel>(context, listen: false).removeAll();