Flutter使用bloc+freezed时Cubit返回null,添加打印代码后功能正常问题求助
问题根本原因
异步方法执行时序混乱导致状态被覆盖
初始化Cubit时同时调用了countDoneNoteOutOfAllNotes()和retrieveData()两个未加等待的异步方法,二者执行顺序不可控。如果retrieveData先执行完成发射getNotes状态,后续countDoneNoteOutOfAllNotes执行完成会发射新的状态覆盖前者,导致Bloc最终持有的状态不是getNotes类型,UI的maybeMap匹配不到对应状态就返回null。
你修改代码后看似恢复正常,只是因为新增的代码人为拉长了retrieveData的执行时长,让countDoneNoteOutOfAllNotes先完成发射状态,最后才是retrieveData发射getNotes状态,属于巧合的时序结果,并不是真正修复了问题。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
相关产品推荐
相关产品推荐

