Skip to content

Flutter 状态管理

什么是状态管理

状态管理是指在应用中管理和共享数据的方式。在 Flutter 中,状态可以是:

  • 局部状态:只在单个 Widget 中使用的状态
  • 全局状态:在多个 Widget 之间共享的状态

状态管理方案

1. setState

这是 Flutter 中最基本的状态管理方式,适用于简单的状态管理场景。

使用场景:单个 Widget 内部的状态管理

示例

dart
class Counter extends StatefulWidget {
  @override
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;

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

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Count: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: Text('Increment'),
        ),
      ],
    );
  }
}

2. Provider

Provider 是 Flutter 官方推荐的状态管理库,它基于 InheritedWidget 实现,提供了一种简单的状态管理方式。

使用场景:中小型应用的状态管理

安装

bash
flutter pub add provider

示例

dart
// 1. 创建数据模型
class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

// 2. 在 Widget 树中提供状态
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MyApp(),
    ),
  );
}

// 3. 消费状态
class CounterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<CounterModel>(
      builder: (context, counter, child) {
        return Column(
          children: [
            Text('Count: ${counter.count}'),
            ElevatedButton(
              onPressed: counter.increment,
              child: Text('Increment'),
            ),
          ],
        );
      },
    );
  }
}

3. Bloc

Bloc (Business Logic Component) 是一种基于流的状态管理方案,使用 Stream 来管理状态。

使用场景:复杂应用的状态管理,特别是需要处理复杂业务逻辑的场景

安装

bash
flutter pub add bloc flutter_bloc

示例

dart
// 1. 定义事件
enum CounterEvent {
  increment,
  decrement,
}

// 2. 创建 Bloc
class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0);

  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    switch (event) {
      case CounterEvent.increment:
        yield state + 1;
        break;
      case CounterEvent.decrement:
        yield state - 1;
        break;
    }
  }
}

// 3. 提供 Bloc
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => CounterBloc(),
      child: MaterialApp(
        home: CounterPage(),
      ),
    );
  }
}

// 4. 消费 Bloc
class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: BlocBuilder<CounterBloc, int>(
        builder: (context, count) {
          return Center(
            child: Text('Count: $count'),
          );
        },
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(CounterEvent.increment),
            child: Icon(Icons.add),
          ),
          SizedBox(height: 10),
          FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(CounterEvent.decrement),
            child: Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

4. Riverpod

Riverpod 是由 Provider 的作者开发的新一代状态管理库,解决了 Provider 的一些局限性。

使用场景:各种规模的应用,特别是需要更灵活状态管理的场景

安装

bash
flutter pub add riverpod flutter_riverpod

示例

dart
// 1. 创建 Provider
final counterProvider = StateProvider<int>((ref) => 0);

// 2. 提供 Provider
void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}

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

5. GetX

GetX 是一个全功能的状态管理库,同时提供了路由管理、依赖注入等功能。

使用场景:快速开发的应用,特别是需要简化路由和依赖注入的场景

安装

bash
flutter pub add get

示例

dart
// 1. 创建控制器
class CounterController extends GetxController {
  var count = 0.obs;

  void increment() {
    count++;
  }
}

// 2. 消费状态
class CounterPage extends StatelessWidget {
  final CounterController controller = Get.put(CounterController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(
        child: Obx(() => Text('Count: ${controller.count}')),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.increment,
        child: Icon(Icons.add),
      ),
    );
  }
}

状态管理方案对比

方案优点缺点适用场景
setState简单直观,无需额外依赖只适用于局部状态,难以在组件间共享单个组件的简单状态
Provider官方推荐,使用简单对于复杂状态管理可能不够灵活中小型应用
Bloc基于流,处理复杂逻辑能力强代码量较大,学习曲线较陡复杂应用
Riverpod灵活,解决了 Provider 的局限性相对较新,生态可能不如 Provider各种规模的应用
GetX功能全面,代码简洁可能过于“魔法”,不利于理解快速开发的应用

状态管理最佳实践

  1. 根据应用规模选择合适的方案

    • 小型应用:setState 或 Provider
    • 中型应用:Provider 或 Riverpod
    • 大型应用:Bloc 或 Riverpod
  2. 保持状态管理的单一职责

    • 每个状态管理单元只负责特定的功能
    • 避免将所有状态都放在一个地方
  3. 使用不可变状态

    • 状态更新时创建新的状态对象,而不是修改现有状态
    • 这有助于避免意外的副作用
  4. 合理使用状态提升

    • 将状态提升到需要访问它的所有组件的共同父组件
    • 避免过度使用全局状态
  5. 测试状态管理逻辑

    • 为状态管理逻辑编写单元测试
    • 确保状态更新符合预期

总结

选择合适的状态管理方案对于 Flutter 应用的开发至关重要。不同的状态管理方案有各自的优缺点,开发者应该根据应用的规模和复杂度选择最适合的方案。无论选择哪种方案,都应该遵循状态管理的最佳实践,确保代码的可维护性和可测试性。

基于 VitePress 的本地知识库