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

Flutter BLOC同步HTTP请求下Widget内容未更新问题

Flutter Bloc同步HTTP请求下Widget不更新问题解决

问题根源

你的代码存在两个核心问题:

  1. 错误创建Bloc实例触发事件:在LoadNotify的请求回调里,你新建了NotifyBloc().add(UpdateList()),这个新的Bloc实例和当前页面通过BlocProvider提供的实例完全无关,状态更新根本无法传递到绑定的Widget。
  2. 对"同步加载"的误解: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:25:24