Flutter BLOC同步HTTP请求下Widget内容未更新问题
Flutter Bloc同步HTTP请求下Widget不更新问题解决
问题根源
你的代码存在两个核心问题:
- 错误创建Bloc实例触发事件:在
LoadNotify的请求回调里,你新建了NotifyBloc().add(UpdateList()),这个新的Bloc实例和当前页面通过BlocProvider提供的实例完全无关,状态更新根本无法传递到绑定的Widget。 - 对"同步加载"的误解:Flutter是单线程模型,在UI线程执行同步阻塞的HTTP请求会直接卡死界面,这是绝对需要避免的。你所谓的"同步加载"需求,本质应该是确保数据加载完成后再渲染内容,而非使用真的同步阻塞请求。
修正方案
方案1:改造回调式请求,直接在回调内emit状态
把回调逻辑改成直接更新状态并emit,不要新建Bloc实例:
on<LoadNotify>((event, emit) { NotifyState res = state.copyWith(); // 推荐用copyWith保持状态一致性,而非新建实例 TRequests req = TRequests(); // 先emit加载状态,让Widget显示加载提示 emit(res.copyWith(isLoading: true)); req.request( "GetListPushMessages", jsonEncode({ "hash": globals.UserInfo["md5hash"], "count": 50, }), (answer) { print("Enter: $answer"); // 直接用当前事件的emit方法更新状态 emit(res.copyWith( NotifyList: answer, isLoading: false )); globals.NotifyList = answer; }, (error) { // 处理错误状态 emit(res.copyWith( error: error.toString(), isLoading: false )); } ); });
注意:建议给NotifyState添加copyWith方法,保证状态不可变性(Bloc最佳实践):
class NotifyState { final List notifyList; final bool isLoading; final String? error; NotifyState({ this.notifyList = const [], this.isLoading = false, this.error, }); // 实现copyWith方法 NotifyState copyWith({ List? notifyList, bool? isLoading, String? error, }) { return NotifyState( notifyList: notifyList ?? this.notifyList, isLoading: isLoading ?? this.isLoading, error: error ?? this.error, ); } NotifyState init() { return NotifyState(); } }
方案2:改用async/await异步请求(推荐)
如果你的TRequests提供了异步版本asyncRequest,用async/await处理会让代码更清晰:
on<LoadNotify>((event, emit) async { // 先emit加载状态 emit(state.copyWith(isLoading: true)); try { TRequests req = TRequests(); http.Response response = await req.asyncRequest( "GetListPushMessages", jsonEncode({ "hash": globals.UserInfo["md5hash"], "count": 50, }), ); Map<String, dynamic> answer = jsonDecode(response.body); // 加载完成,emit数据状态 emit(state.copyWith( notifyList: answer["result"], isLoading: false, )); globals.NotifyList = answer["result"]; } catch (e) { // 捕获并处理请求错误 emit(state.copyWith( error: e.toString(), isLoading: false, )); } });
实现"数据加载完成后再渲染"的需求
如果要确保页面渲染前完成数据加载,可以:
- 在Widget的
initState触发加载事件,同时根据Bloc的isLoading状态显示加载占位符,直到数据加载完成后再展示内容。 - 禁止使用
sleep这类阻塞方法,它会直接冻结UI,完全不符合Flutter的运行机制。
内容的提问来源于stack exchange,提问作者Pavel Gribov
相关产品推荐
相关产品推荐

