在Flutter开发中,状态管理始终是架构设计的核心问题。随着项目复杂度提升,如何优雅地管理数据流、实现UI与逻辑解耦?Bloc和Cubit作为Flutter官方推荐的状态管理方案,凭借清晰的架构设计可预测的状态流脱颖而出。

  • Bloc:通过事件驱动状态变更,适合需要追踪操作来源的复杂场景
  • Cubit:简化版Bloc,通过方法直接触发变更,适合轻量级场景

一、快速安装

flutter pub add flutter_bloc

二、Cubit计数器示例使用理解

2.1 Cubit方式定义以及使用

// counter_cubit.dart
// 定义一个存储计数器的cubit  状态是 int类型的
import 'package:flutter_bloc/flutter_bloc.dart';

class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  // 提供外界修改状态的函数
  void increment() {
    emit(state + 1);
  }

  void decrement() {
    emit(state - 1);
  }
}

代码解读:

  • 继承Cubit<int>指定状态类型为int
  • emit()方法触发状态更新
  • 业务逻辑完全封装在Cubit内部

2.2 Cubit 状态的获取以及修改

class TestPage extends StatelessWidget {
  const TestPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text("cubit"),
        ),
        body: BlocProvider(
            create: (_) => CounterCubit(),
            child: ShowPage())
    );
  }
}

class ShowPage extends StatelessWidget {
  const ShowPage({super.key});

  
  Widget build(BuildContext context) {
    return Column(children: [
      BlocBuilder<CounterCubit, int>(
        builder: (context, state) {
          return Text(
            "number: $state",
            style: Theme.of(context).textTheme.headlineMedium,
          );
        },
      ),
      TextButton(onPressed: () {
          // 利用上下文获取状态数据中提供的方法改变数据
        context.read<CounterCubit>().increment();
      }, child: Text("add")),
      TextButton(onPressed: () {
        context.read<CounterCubit>().decrement();
      }, child: Text("sub"))
    ],);
  }
}

关键技术点

  • BlocProvider:将某个状态数据提供给某个组件使用
  • BlocBuilder:获取状态数据提供组件渲染使用的

3.3 Cubit方式监听状态的变化

  • 方式一:在Cubit中重写onChange方法
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() {
    emit(state + 1);
  }

  void decrement() {
    emit(state - 1);
  }

  
  void onChange(Change<int> change) {
    // 当状态改变时候,会调用改方法
    debugPrint("***** CounterCubit onChange $change");
    super.onChange(change);
  }
}
  • 方式二:创建BlocObserver重写onChange方法
// 创建BlocObserver
import 'package:bloc/bloc.dart';
import 'package:flutter/foundation.dart';

class CounterObserver extends BlocObserver {
  const CounterObserver();

  
  void onChange(BlocBase<dynamic> bloc, Change<dynamic> change) {
    super.onChange(bloc, change);
    debugPrint('CounterObserver --- ${bloc.runtimeType} $change');
  }
}

// 使用BlocObserver
class ShowPage extends StatelessWidget {
  const ShowPage({super.key});

  
  Widget build(BuildContext context) {

    // 演示在这里设置监听
    Bloc.observer = CounterObserver();

    return Column(children: [
      BlocBuilder<CounterCubit, int>(
        builder: (context, state) {
          return Text(
            "number: $state",
            style: Theme.of(context).textTheme.headlineMedium,
          );
        },
      ),
      TextButton(onPressed: () {
        context.read<CounterCubit>().increment();
      }, child: Text("add")),
      TextButton(onPressed: () {
        context.read<CounterCubit>().decrement();
      }, child: Text("sub"))
    ],);
  }
}

三、Bloc计数器示例使用理解

3.1 Bloc方式定义以及使用

// counter_bloc.dart 定义

import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

sealed class CounterEvent {}

// 定义event事件
final class CounterIncrementPressed extends CounterEvent {}

final class CounterDecrementPressed extends CounterEvent {}

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
      // 对应event事件的处理
    on<CounterIncrementPressed>((event, emit) {
      debugPrint("CounterBloc");
      emit(state + 1);
    });

    on<CounterDecrementPressed>((event, emit) {
      emit(state - 1);
    });
  }
}

设计优势

  • 明确的事件-状态映射关系
  • 支持异步操作和复杂事件处理
  • 完整的操作历史追溯能力

3.2 Bloc 状态的获取以及修改

class TestPage extends StatelessWidget {
  const TestPage({super.key});

  
  Widget build(BuildContext context) {

    return Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text("bloc"),
        ),
        body: BlocProvider(
            create: (_) => CounterBloc(),
            child: ShowPage())
    );
  }
}

class ShowPage extends StatelessWidget {
  const ShowPage({super.key});

  
  Widget build(BuildContext context) {
    return Column(children: [
      BlocBuilder<CounterBloc, int>(
        builder: (context, state) {
          return Text(
            "number: $state",
            style: Theme.of(context).textTheme.headlineMedium,
          );
        },
      ),
      TextButton(onPressed: () {
          // 发送event事件
        context.read<CounterBloc>().add(CounterIncrementPressed());
      }, child: Text("add")),
      TextButton(onPressed: () {
        context.read<CounterBloc>().add(CounterDecrementPressed());
      }, child: Text("sub"))
    ],);
  }
}

四、Cubit和Bloc的优缺点

特性 Cubit Bloc
代码复杂度 ⭐️⭐️⭐️⭐️⭐️(简单) ⭐️⭐️⭐️(中等)
事件追溯能力 ⭐️⭐️⭐️⭐️⭐️
学习曲线 平缓 较陡
适合场景 简单状态管理 复杂业务逻辑
测试便利性 简单 需要模拟事件

根据Cubit和Bloc上面的使用情况以及对官方文档的阅读理解

Cubit相对于Bloc模板代码量更少,只需要定义状态以及修改状态的函数,更容易理解

Bloc则需要定义状态、event事件、处理event事件的操作等,相对于Cubit的优势是能了解状态的变化以及触发状态变化的原因event。

选型建议

  • 小型项目/简单状态 → Cubit
  • 中大型项目/需要事件溯源 → Bloc
  • 渐进式迁移:从Cubit开始,必要时升级Bloc

更多推荐