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

Flutter 网络恢复时自动重载Bloc轮播组件未加载数据方案

实现方案

你现有项目已经集成了connectivity_wrapper,无需额外引入依赖即可完成网络状态监听和自动重载逻辑,核心改动点如下:

  • 在组件状态类中新增网络状态流订阅实例、数据加载成功标记位
  • 初始化时订阅网络变化事件,仅当网络从断开恢复连接、且轮播数据未加载成功时,主动触发数据重载
  • 监听Bloc状态变化同步加载标记,避免数据加载完成后重复触发无效请求
  • 组件销毁时注销网络订阅,避免内存泄漏
  • 优化错误状态UI,避免纯空白无提示的问题

具体代码改动

1. 修改状态类的生命周期和变量定义

class _MonkCarouselState extends State<MonkCarousel> {
  // 网络状态变化订阅
  late StreamSubscription _connectivitySub;
  // 标记轮播数据是否已加载成功
  bool _dataLoaded = false;

  _loadMonks() async {
    if (await ConnectivityWrapper.instance.isConnected) {
      context.read<LatestMonkBloc>().add(const GetLastMonksEvent(5));
    }
  }

  @override
  void initState() {
    super.initState();
    _loadMonks();
    // 监听网络状态变更
    _connectivitySub = ConnectivityWrapper.instance.onConnectivityChanged.listen((connected) {
      // 网络恢复且数据未加载完成时自动重试
      if (connected && !_dataLoaded) {
        _loadMonks();
      }
    });
  }

  @override
  void dispose() {
    // 注销订阅防止内存泄漏
    _connectivitySub.cancel();
    super.dispose();
  }

2. 用BlocListener包裹原有BlocBuilder,同步加载状态

把原有BlocBuilder外层嵌套BlocListener,用来监听Bloc状态更新加载标记,同时优化错误状态的UI展示:

// 替换原有child位置的BlocBuilder代码
child: BlocListener<LatestMonkBloc, LatestMonkState>(
  listener: (context, state) {
    _dataLoaded = state is LatestMonkLoaded;
  },
  child: BlocBuilder<LatestMonkBloc, LatestMonkState>(
    builder: (context, state) {
      if (state is LatestMonkError) {
        return Container(
          width: MediaQuery.of(context).size.width,
          margin: const EdgeInsets.symmetric(horizontal: 10),
          padding: const EdgeInsets.all(16),
          decoration: BoxDecoration(
            color: Theme.of(context).scaffoldBackgroundColor,
            borderRadius: BorderRadius.circular(20),
          ),
          child: const Center(
            child: Text("数据加载失败,网络恢复后将自动重试"),
          ),
        );
      } else if (state is LatestMonkLoaded) {
        // 原有CarouselSlider逻辑完全保留,不需要修改
        return CarouselSlider(
          options: CarouselOptions(
            height: 160,
            autoPlay: true,
            autoPlayCurve: Curves.fastOutSlowIn,
            enableInfiniteScroll: true,
            autoPlayAnimationDuration: const Duration(milliseconds: 800),
            viewportFraction: 0.5,
          ),
          items: state.monks.map((monk) {
            return Builder(
              builder: (BuildContext context) {
                return GestureDetector(
                  onTap: () {
                    pushNewScreen(context,
                        screen: SongScreen(
                          monk: monk,
                          album: Album(id: monk.id, monkId: monk.id, title: kLatestDhama),
                          screenMode: SongScreenMode.latest,
                        ),
                        pageTransitionAnimation:
                        PageTransitionAnimation.scale);
                  },
                  child: Container(
                    width: MediaQuery.of(context).size.width,
                    margin: const EdgeInsets.symmetric(horizontal: 10),
                    padding: const EdgeInsets.only(left: 5, right: 5, top: 0),
                    decoration: BoxDecoration(
                      color: Theme.of(context).scaffoldBackgroundColor,
                      borderRadius: BorderRadius.circular(20),
                    ),
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        CachedNetworkImage(
                          width: 100.0,
                          height: 100.0,
                          imageUrl: monk.imageUrl,
                          imageBuilder: (context, imageProvider) =>
                              Container(
                                decoration: BoxDecoration(
                                  borderRadius: BorderRadius.circular(10),
                                  image: DecorationImage(
                                    image: imageProvider,
                                    fit: BoxFit.cover,
                                  ),
                                ),
                              ),
                          placeholder: (context, url) =>
                              Container(color: Colors.black12),
                          errorWidget: (context, url, error) => const Icon(
                            Icons.error,
                            size: 100,
                            color: Colors.red,
                          ),
                        ),
                        const SizedBox(height: 5),
                        Flexible(
                          child: AutoSizeText(
                            monk.title,
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: const TextStyle(fontSize: 15),
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              },
            );
          }).toList(),
        );
      }
      return const CircularProgressIndicatorWidget();
    },
  ),
),

注意事项

  • 如果你当前使用的connectivity_wrapper版本中,onConnectivityChanged返回的是ConnectivityResult枚举而非bool值,只需要把判断条件从if (connected && !_dataLoaded)改成if (result != ConnectivityResult.none && !_dataLoaded)即可,逻辑完全一致
  • 加载标记_dataLoaded会在数据加载成功时自动置为true,避免网络频繁切换时重复发起已经成功的接口请求,减少资源消耗
  • 错误状态增加文字提示后,用户不会看到无反馈的空白区块,交互体验更友好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:39:13