应用程序的状态
学习在 Flutter 中管理应用状态。
什么是状态?
状态指的是在应用程序生命周期中发生变化的数据。它是应用程序所操作的数据,用户界面(UI)根据应用当前的状态生成。
状态对象在多次调用 build() 方法之间保持持久性,使得它们能够在 UI 重建之间记住信息。
状态的分类
我们可以将 Flutter 中的状态分为两类:
- 临时状态(Ephemeral state)
- 应用状态(App state)
临时状态
临时状态,也称为 UI 状态或局部状态,是包含在单个 UI 组件内的状态。这类状态通常仅由当前组件使用,不需要被应用中的其他组件访问。
临时状态的示例包括:
BottomNavigationBar中当前选中的标签- 复选框或单选按钮的当前状态
- 某个组件内文本字段的值
1class MyHomepage extends StatefulWidget { 2 const MyHomepage({super.key}); 3 4 5 State<MyHomepage> createState() => _MyHomepageState(); 6} 7 8class _MyHomepageState extends State<MyHomepage> { 9 int _index = 0; 10 11 12 Widget build(BuildContext context) { 13 return BottomNavigationBar( 14 currentIndex: _index, 15 onTap: (newIndex) { 16 setState(() { 17 _index = newIndex; 18 }); 19 }, 20 // ... 项目 ... 21 ); 22 } 23}
在上述示例中,底部导航栏中当前激活标签的位置存储在 _MyHomepageState 类的 _index 字段中。在此例中,_index 是一个临时状态,因此只能在 _MyHomepageState 类内部访问。
应用状态
应用状态指的是应用中多个组件共享的状态。我们可能还希望在不同用户会话之间保留这种状态。
应用状态的示例包括:
- 用户偏好设置
- 认证或授权信息
- 社交类应用中的通知
- 电商应用中的购物车
- 新闻类应用中文章的已读/未读状态
如何管理状态
状态管理是我们处理应用程序状态的方法。临时状态可以使用 State 和 setState() 来管理。
而应用状态则更为复杂,可以通过 Flutter 的 InheritedWidget 或各种状态管理包来处理,例如:
- Provider
- Riverpod
- BLoC
1import 'package:flutter/material.dart'; 2 3void main() { 4 runApp(const BrightnessMode(mode: Brightness.dark, child: MyApp())); 5} 6 7class BrightnessMode extends InheritedWidget { 8 const BrightnessMode({super.key, required this.mode, required super.child}); 9 10 final Brightness mode; 11 12 static BrightnessMode of(BuildContext context) { 13 final BrightnessMode? result = 14 context.dependOnInheritedWidgetOfExactType<BrightnessMode>(); 15 assert(result != null, 'No BrightnessMode found in context'); 16 return result!; 17 } 18 19 20 bool updateShouldNotify(BrightnessMode oldWidget) => mode != oldWidget.mode; 21} 22 23class MyApp extends StatelessWidget { 24 const MyApp({super.key}); 25 26 27 Widget build(BuildContext context) { 28 return MaterialApp( 29 title: 'InheritedWidget Demo', 30 theme: ThemeData( 31 primarySwatch: Colors.blue, 32 brightness: BrightnessMode.of(context).mode, 33 ), 34 home: const MyHomePage(), 35 ); 36 } 37} 38 39class MyHomePage extends StatelessWidget { 40 const MyHomePage({super.key}); 41 42 43 build(context) { 44 return Scaffold( 45 appBar: AppBar(title: const Text('Inherited Widget')), 46 body: Center( 47 child: Column( 48 mainAxisAlignment: MainAxisAlignment.center, 49 children: <Widget>[ 50 Text( 51 'You are on ${BrightnessMode.of(context).mode == Brightness.dark ? 'dark' : 'light'} mode'), 52 ], 53 ), 54 ), 55 ); 56 } 57}
在上述代码片段中,应用的亮度通过 BrightnessMode 类的 mode 属性获取。mode 对象的当前值可通过 BrightnessMode.of(context) 方法被 BrightnessMode 组件的所有子组件访问。在这个例子中,mode 对象是一个应用状态,因为它可以在应用的其他组件中被访问。
如何选择状态管理方案
你可能需要进一步研究以决定为应用状态管理选择哪种方案。你的选择将取决于应用的性质和复杂程度、团队(或你自己)的经验以及项目的其他因素。
有效的状态管理之所以重要,原因如下:
- 可以轻松地在应用中共享状态。
- 开发者可以添加新功能而不破坏现有逻辑。
- 应用的 UI 与业务逻辑分离。
- 应用保持可测试性。
在本章中,我们将使用以下几种状态管理技术来管理下方 TODO 应用的状态:
- Flutter 的
setState方法 - Flutter 的
InheritedWidget类 - Provider 包
- 业务逻辑组件(BLoC)
- 依赖注入
- Riverpod 包