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

Flutter Bloc emit调用报错:事件处理完成后调用emit问题求助

解决Bloc中emit调用时机错误问题

问题场景

实现聊天功能(未使用WebSocket,后端运行正常),编写的ChatBloc代码如下:

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:moms/features/chat/domain/entities/message_entity.dart';
import 'package:moms/features/chat/domain/usecases/send_message.dart';
import 'package:moms/features/chat/domain/usecases/get_messages.dart';
import 'package:moms/features/chat/domain/usecases/get_or_create_thread_usecase.dart';

part 'chat_event.dart';
part 'chat_state.dart';

class ChatBloc extends Bloc<ChatEvent, ChatState> {
  final GetOrCreateThread getOrCreateThread;
  final GetMessages getMessages;
  final SendMessage sendMessage;

  ChatBloc({
    required this.getOrCreateThread,
    required this.getMessages,
    required this.sendMessage,
  }) : super(ChatInitial()) {
    on<LoadChatThreadEvent>(_onLoadChatThreadEvent);
    on<LoadMessagesEvent>(_onLoadMessagesEvent);
    on<SendMessageEvent>(_onSendMessageEvent);
  }

  Future<void> _onLoadChatThreadEvent(
      LoadChatThreadEvent event, Emitter<ChatState> emit) async {
    emit(ChatLoading());

    final threadResult = await getOrCreateThread(event.gigId, event.bidId);
    threadResult.fold(
      (failure) =>
          emit(ChatError('Failed to load chat thread: ${failure.message}')),
      (threadId) async {
        await _loadMessagesForThread(threadId, emit);
      },
    );
  }

  Future<void> _onLoadMessagesEvent(
      LoadMessagesEvent event, Emitter<ChatState> emit) async {
    emit(ChatLoading());
    await _loadMessagesForThread(event.threadId, emit);
  }

  Future<void> _onSendMessageEvent(
      SendMessageEvent event, Emitter<ChatState> emit) async {
    emit(ChatLoading());

    final sendResult =
        await sendMessage(event.threadId, event.content, event.senderId);
    sendResult.fold(
      (failure) =>
          emit(ChatError('Failed to send message: ${failure.message}')),
      (message) async {
        await _loadMessagesForThread(event.threadId, emit);
      },
    );
  }

  Future<void> _loadMessagesForThread(
      int threadId, Emitter<ChatState> emit) async {
    final messagesResult = await getMessages(threadId);
    messagesResult.fold(
      (failure) =>
          emit(ChatError('Failed to load messages: ${failure.message}')),
      (messages) => emit(ChatLoaded(threadId: threadId, messages: messages)),
    );
  }
}

运行后反复出现如下报错:

E/flutter (18794): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:bloc/src/emitter.dart': Failed assertion: line 114 pos 7: '!_isCompleted': 
E/flutter (18794): emit was called after an event handler completed normally.
E/flutter (18794): This is usually due to an unawaited future in an event handler.
E/flutter (18794): Please make sure to await all asynchronous operations with event handlers
E/flutter (18794): and use emit.isDone after asynchronous operations before calling emit() to
E/flutter (18794): ensure the event handler has not completed.
E/flutter (18794): 
E/flutter (18794):   **BAD**
E/flutter (18794):   on<Event>((event, emit) {
E/flutter (18794):     future.whenComplete(() => emit(...));
E/flutter (18794):   });
E/flutter (18794): 
E/flutter (18794):   **GOOD**
E/flutter (18794):   on<Event>((event, emit) async {
E/flutter (18794):     await future.whenComplete(() => emit(...));
E/flutter (18794):   });
E/flutter (18794): 
E/flutter (18794): #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:50:61)
E/flutter (18794): #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
E/flutter (18794): #2      _Emitter.call (package:bloc/src/emitter.dart:114:7)
E/flutter (18794): #3      ChatBloc._loadMessagesForThread.<anonymous closure> (package:project/features/chat/presentation/bloc/chat_bloc.dart:66:25)
E/flutter (18794): #4      Right.fold (package:dartz/src/either.dart:200:64)
E/flutter (18794): #5      ChatBloc._loadMessagesForThread (package:project/features/chat/presentation/bloc/chat_bloc.dart:63:20)
E/flutter (18794): <asynchronous suspension>
E/flutter (18794): #6      ChatBloc._onLoadChatThreadEvent.<anonymous closure> (package:project/features/chat/presentation/bloc/chat_bloc.dart:34:9)
E/flutter (18794): <asynchronous suspension>

错误原因

问题出在fold方法的使用上:fold是同步方法,当你在Right分支传入一个async匿名函数时,该函数会返回一个Future,但fold不会等待这个Future完成。这会导致事件处理器(比如_onLoadChatThreadEvent)在fold执行完毕后就提前结束,而后续_loadMessagesForThread中的emit调用会在事件处理器已经完成后执行,触发Bloc的断言检查。

修复方案

将fold替换为显式的Left/Right类型判断,这样可以直接await异步操作,确保事件处理器等待所有异步逻辑完成后再结束:

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:moms/features/chat/domain/entities/message_entity.dart';
import 'package:moms/features/chat/domain/usecases/send_message.dart';
import 'package:moms/features/chat/domain/usecases/get_messages.dart';
import 'package:moms/features/chat/domain/usecases/get_or_create_thread_usecase.dart';
import 'package:dartz/dartz.dart';

part 'chat_event.dart';
part 'chat_state.dart';

class ChatBloc extends Bloc<ChatEvent, ChatState> {
  final GetOrCreateThread getOrCreateThread;
  final GetMessages getMessages;
  final SendMessage sendMessage;

  ChatBloc({
    required this.getOrCreateThread,
    required this.getMessages,
    required this.sendMessage,
  }) : super(ChatInitial()) {
    on<LoadChatThreadEvent>(_onLoadChatThreadEvent);
    on<LoadMessagesEvent>(_onLoadMessagesEvent);
    on<SendMessageEvent>(_onSendMessageEvent);
  }

  Future<void> _onLoadChatThreadEvent(
      LoadChatThreadEvent event, Emitter<ChatState> emit) async {
    emit(ChatLoading());

    final threadResult = await getOrCreateThread(event.gigId, event.bidId);
    if (threadResult is Left) {
      final failure = threadResult.value;
      emit(ChatError('Failed to load chat thread: ${failure.message}'));
    } else {
      final threadId = (threadResult as Right).value;
      await _loadMessagesForThread(threadId, emit);
    }
  }

  Future<void> _onLoadMessagesEvent(
      LoadMessagesEvent event, Emitter<ChatState> emit) async {
    emit(ChatLoading());
    await _loadMessagesForThread(event.threadId, emit);
  }

  Future<void> _onSendMessageEvent(
      SendMessageEvent event, Emitter<ChatState> emit) async {
    emit(ChatLoading());

    final sendResult = await sendMessage(event.threadId, event.content, event.senderId);
    if (sendResult is Left) {
      final failure = sendResult.value;
      emit(ChatError('Failed to send message: ${failure.message}'));
    } else {
      await _loadMessagesForThread(event.threadId, emit);
    }
  }

  Future<void> _loadMessagesForThread(
      int threadId, Emitter<ChatState> emit) async {
    final messagesResult = await getMessages(threadId);
    if (messagesResult is Left) {
      final failure = messagesResult.value;
      emit(ChatError('Failed to load messages: ${failure.message}'));
    } else {
      final messages = (messagesResult as Right).value;
      emit(ChatLoaded(threadId: threadId, messages: messages));
    }
  }
}

额外说明

如果坚持使用fold,可以将分支函数改为返回Future,并通过await整个fold的结果,但这种写法可读性较差:

// 以_onLoadChatThreadEvent为例
await threadResult.fold(
  (failure) async {
    emit(ChatError('Failed to load chat thread: ${failure.message}'));
  },
  (threadId) async {
    await _loadMessagesForThread(threadId, emit);
  },
);

显式的类型判断代码更直观,更适合新手维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:17:05