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

Flutter使用bloc+freezed时Cubit返回null,添加打印代码后功能正常问题求助

问题根本原因

  1. 异步方法执行时序混乱导致状态被覆盖
    初始化Cubit时同时调用了countDoneNoteOutOfAllNotes()和retrieveData()两个未加等待的异步方法,二者执行顺序不可控。如果retrieveData先执行完成发射getNotes状态,后续countDoneNoteOutOfAllNotes执行完成会发射新的状态覆盖前者,导致Bloc最终持有的状态不是getNotes类型,UI的maybeMap匹配不到对应状态就返回null。
    你修改代码后看似恢复正常,只是因为新增的代码人为拉长了retrieveData的执行时长,让countDoneNoteOutOfAllNotes先完成发射状态,最后才是retrieveData发射getNotes状态,属于巧合的时序结果,并不是真正修复了问题。

  2. UI状态取值逻辑本身存在缺陷
    你将笔记总数、笔记列表拆成了两个独立的Freezed状态,但Bloc同一时间只会持有一个状态,不可能同时匹配到getNotesCount和getNotes两个状态:要么能拿到列表总数拿不到列表内容,要么能拿到列表内容拿不到总数,逻辑上本身就无法正常运行。

排查方法

  • 在Cubit的每个emit调用前打印状态类型和内容,确认状态发射的顺序和最终持有的状态是否符合预期
  • 梳理UI展示需要的所有数据,确认是否需要拆分为多个独立状态

修复方案

步骤1:合并关联数据到同一状态

将页面展示需要的笔记列表、总数、已完成计数等关联数据放到同一个状态内,避免状态互相覆盖:

@freezed
class ScheduledNotesState with _$ScheduledNotesState {
  const factory ScheduledNotesState.initial() = _Initial;
  const factory ScheduledNotesState.loading() = _Loading;
  const factory ScheduledNotesState.loadSuccess({
    required List<Map<String, dynamic>> notes,
    required int noteCount,
    required String doneCountStr,
  }) = _LoadSuccess;
  const factory ScheduledNotesState.updateIsDoneNote({required int updateIsDoneNote}) = _UpdateIsDoneNote;
  const factory ScheduledNotesState.error(String msg) = _Error;
}

步骤2:调整Cubit异步逻辑

异步操作按顺序执行,统一发射包含所有必要数据的状态:

@injectable
class ScheduledNotesCubit extends Cubit<ScheduledNotesState> {
  ScheduledNotesCubit(this._noteRepository)
      : super(const ScheduledNotesState.initial());
  final NoteRepository _noteRepository;

  Future<void> loadPageData() async {
    emit(const ScheduledNotesState.loading());
    try {
      // 按顺序执行异步请求
      final doneCountStr = await countDoneNoteOutOfAllNotes();
      final notes = await _noteRepository.retrieveData();
      // 统一发射包含所有需要数据的状态
      emit(ScheduledNotesState.loadSuccess(
        notes: notes,
        noteCount: notes.length,
        doneCountStr: doneCountStr,
      ));
    } catch (e) {
      emit(ScheduledNotesState.error(e.toString()));
    }
  }

  Future<String> countDoneNoteOutOfAllNotes() async {
    // 保留原有实现逻辑,返回结果即可,无需单独发射状态
  }
}

步骤3:调整UI状态分支处理逻辑

按状态类型分支处理渲染逻辑,避免跨状态取值:

class TodayPage extends HookWidget {
  const TodayPage();
  @override
  Widget build(BuildContext context) {
    return BlocProvider<ScheduledNotesCubit>(
      lazy:false,
      create: (context) => getIt<ScheduledNotesCubit>()..loadPageData(),
      child: BlocBuilder<ScheduledNotesCubit, ScheduledNotesState>(
        builder: (context, state) {
          return state.when(
            initial: () => const SizedBox.shrink(),
            loading: () => const Center(child: CircularProgressIndicator()),
            loadSuccess: (notes, noteCount, doneCountStr) => ListView.builder(
              itemCount: noteCount,
              itemBuilder: (context, index) => Text(notes[index]['content'] ?? ''),
            ),
            updateIsDoneNote: (updateId) => const SizedBox.shrink(), // 补充对应更新逻辑
            error: (msg) => Center(child: Text(msg)),
          );
        },
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 19:15:03