1.5. 状态管理

状态管理是 Flutter 应用的核心问题。随着应用规模增长,合理的状态管理方案至关重要。

1.5.1. 什么是状态

状态(State) 是会影响 UI 渲染的任何数据。

状态类型
├── 本地(Ephemeral)状态:单个 Widget 内使用
│   └── TextField 的当前输入、当前页码
└── 应用(App)状态:多个模块共享
    └── 登录信息、购物车、主题设置、语言偏好

小技巧

用 "是否需要多个 Widget 共享" 来选择方案: - 仅本 Widget 使用 → StatefulWidget + setState - 需要共享 → 选择一种全局状态管理方案

1.5.2. setState(基础方案)

适合纯本地状态:

class CounterPage extends StatefulWidget {
  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child: Text('$_count')),
      floatingActionButton: FloatingActionButton(
        onPressed: _increment,
        child: const Icon(Icons.add),
      ),
    );
  }
}

小心

setState 在 Widget 树变大时性能下降。如果多层级间需要传递状态, 应避免"逐层回调"的方式。

1.5.3. InheritedWidget(框架级)

Flutter 框架内置的共享状态机制:

class ThemeProvider extends InheritedWidget {
  const ThemeProvider({
    super.key,
    required this.isDarkMode,
    required super.child,
  });

  final bool isDarkMode;

  static ThemeProvider of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<ThemeProvider>()!;
  }

  @override
  bool updateShouldNotify(ThemeProvider oldWidget) {
    return isDarkMode != oldWidget.isDarkMode;
  }
}

1.5.4. Provider(推荐入门)

Provider 是官方推荐的基础状态管理方案,封装了 InheritedWidget:

1.5.4.1. 添加依赖

pubspec.yaml
dependencies:
  provider: ^6.0.0

1.5.4.2. 定义模型

class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();   // 通知监听者重建 UI
  }
}

1.5.4.3. 注入与消费

// 注入(通常在 main.dart)
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => CounterModel(),
      child: const MyApp(),
    ),
  );
}

// 消费(在 Widget 中)
class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = context.watch<CounterModel>();  // 监听变化
    return Scaffold(
      body: Center(child: Text('${counter.count}')),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read<CounterModel>().increment(),
        child: const Icon(Icons.add),
      ),
    );
  }
}

重要

  • context.watch<T>():当 T 变化时重建当前 Widget

  • context.read<T>():获取 T 但不监听变化

1.5.5. Riverpod(进阶推荐)

Riverpod 是 Provider 的升级版,编译安全、独立于 Widget 树。

1.5.5.1. 添加依赖

pubspec.yaml
dependencies:
  flutter_riverpod: ^2.0.0

1.5.5.2. 定义与使用

// 定义 Provider
final counterProvider = StateProvider<int>((ref) => 0);

// 异步 Provider
final userProvider = FutureProvider<User>((ref) async {
  return fetchUser();
});

// 消费
class CounterWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return ElevatedButton(
      onPressed: () => ref.read(counterProvider.notifier).state++,
      child: Text('$count'),
    );
  }
}

小技巧

Riverpod 相比 Provider 的优势: - 无需 BuildContext 即可访问状态 - 编译时检查(不会出现 ProviderNotFoundException) - 支持自动取消(autoDispose) - 更好的测试支持

1.5.6. Bloc(事件驱动)

Bloc 基于事件驱动模型,适合复杂业务逻辑。

1.5.6.1. 添加依赖

pubspec.yaml
dependencies:
  flutter_bloc: ^8.0.0

1.5.6.2. 定义 Bloc

// 事件
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}

// Bloc
class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<Increment>((event, emit) => emit(state + 1));
    on<Decrement>((event, emit) => emit(state - 1));
  }
}

1.5.6.3. 使用 Bloc

// 注入
BlocProvider(
  create: (_) => CounterBloc(),
  child: const CounterPage(),
)

// 消费
BlocBuilder<CounterBloc, int>(
  builder: (context, count) {
    return Text('$count');
  },
)

1.5.7. 状态管理方案对比

方案

复杂度

学习曲线

适用规模

核心概念

setState

极低

★☆☆☆☆

极小型

本地状态

Provider

低

★★☆☆☆

中小型

ChangeNotifier

Riverpod

中

★★★☆☆

中大型

Provider/Ref

Bloc

高

★★★★☆

大型

Event/State

GetX

中

★★☆☆☆

中大型

Reactive

备注

对于新项目,推荐从 Provider 或 Riverpod 开始。 当业务逻辑足够复杂、需要明确的事件流管理时,再引入 Bloc。