You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Flutter Bloc Todo示例实现两步流转并同步状态?

扩展Todo流转的BLoC实现方案

核心实现方案

方案1:双Bloc监听仓库单Todo流(推荐)

这是最贴合BLoC单向数据流理念的方案,依赖仓库作为单一数据源,避免Bloc间直接耦合:

  1. 仓库层改造:在现有Todo仓库中添加获取单个Todo的Stream<Todo>方法,基于全局Todo流做过滤,只输出指定ID的Todo变更:
    class TodosRepository {
      final _todosStreamController = BehaviorSubject<List<Todo>>();
      
      // 原有增删改查方法...
      
      Stream<Todo> watchTodo(String todoId) {
        return _todosStreamController.stream
            .map((todos) => todos.firstWhere((todo) => todo.id == todoId));
      }
    }
    
  2. TodoDetailsBloc实现:初始化时传入todoId,在生命周期内监听仓库的watchTodo流,收到变更后同步更新自身状态:
    class TodoDetailsBloc extends Bloc<TodoDetailsEvent, TodoDetailsState> {
      final TodosRepository _repository;
      final String _todoId;
      late StreamSubscription<Todo> _todoSubscription;
      
      TodoDetailsBloc({required TodosRepository repository, required String todoId})
          : _repository = repository,
            _todoId = todoId,
            super(TodoDetailsLoading()) {
        on<LoadTodoDetails>((event, emit) {
          _todoSubscription = _repository.watchTodo(_todoId).listen((todo) {
            add(TodoDetailsUpdated(todo));
          });
        });
        
        on<TodoDetailsUpdated>((event, emit) {
          emit(TodoDetailsLoaded(todo: event.todo));
        });
      }
      
      @override
      Future<void> close() {
        _todoSubscription.cancel();
        return super.close();
      }
    }
    
  3. EditTodoBloc调整:保留原有编辑逻辑,仅负责将修改后的Todo提交到仓库,无需处理状态同步——仓库更新后会自动通过流通知TodoDetailsBloc:
    class EditTodoBloc extends Bloc<EditTodoEvent, EditTodoState> {
      final TodosRepository _repository;
      
      EditTodoBloc({required TodosRepository repository, required Todo initialTodo})
          : _repository = repository,
            super(EditTodoLoaded(todo: initialTodo)) {
        on<UpdateTodo>((event, emit) async {
          await _repository.updateTodo(event.updatedTodo);
          emit(EditTodoSuccess());
        });
      }
    }
    
  4. 页面流转逻辑:
    • 列表页点击Todo,携带todoId跳转详情页并初始化TodoDetailsBloc
    • 详情页点击编辑,携带当前Todo跳转编辑页并初始化EditTodoBloc
    • 编辑页提交后返回详情页,TodoDetailsBloc已通过仓库流收到更新,自动刷新UI

方案2:Bloc间直接通信(场景限定)

如果不想依赖仓库的单Todo流,可通过Bloc间状态监听实现,但耦合度较高,适合小型项目:

  1. 父Widget共享Bloc:在列表页或更高层级注入TodoDetailsBloc,编辑页通过context.read<TodoDetailsBloc>()获取实例,提交后直接发送更新事件:
    // 编辑页提交按钮逻辑
    onPressed: () {
      final updatedTodo = _saveFormData();
      context.read<EditTodoBloc>().add(UpdateTodo(updatedTodo));
      context.read<TodoDetailsBloc>().add(TodoDetailsUpdated(updatedTodo));
      Navigator.pop(context);
    }
    
  2. BlocListener监听状态:在详情页添加BlocListener<EditTodoBloc, EditTodoState>,当EditTodoBloc发出成功状态时,主动触发详情页重新加载:
    BlocListener<EditTodoBloc, EditTodoState>(
      listener: (context, state) {
        if (state is EditTodoSuccess) {
          context.read<TodoDetailsBloc>().add(LoadTodoDetails());
        }
      },
      child: // 详情页UI组件
    )
    

复杂示例参考

可以参考以下多层BLoC状态同步架构:

  • 构建TodosListBloc→TodoDetailsBloc→EditTodoBloc的三层结构,所有Bloc依赖同一个TodosRepository
  • 仓库层同时维护全局Todo列表流和单个Todo的过滤流,确保全页面状态统一
  • 给每个Bloc添加错误处理逻辑,比如加载失败、提交失败的状态分支,提升页面健壮性
  • 编辑页提交后,仓库更新数据源,列表、详情页的Bloc自动同步最新状态

内容的提问来源于stack exchange,提问作者Gohu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:01:07