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

Flutter infinite_scroll_pagination下拉刷新数据重复问题求助

问题解决:下拉刷新数据重复加载

核心问题分析

  • 重复注册请求监听:initState中两次调用_pagingController.addPageRequestListener,导致同一页请求被触发多次,数据重复加载。
  • 刷新逻辑冗余:_refreshList里用setState包裹_pagingController.refresh()完全没必要,refresh()本身会自动通知UI更新。
  • 状态赋值逻辑错误:直接将listingState.itemList赋值给_pagingController.value.itemList,刷新时若Bloc未重置数据,旧数据会与新数据叠加。
  • 加载状态控制混乱:_isLoadingStarted的逻辑未正确重置,导致后续加载状态判断失效。

修复后的代码

class _AdListSliverGridState extends State<AdListSliverGrid> {
  final AdListSliverGridBloc _bloc = AdListSliverGridBloc();
  final PagingController<int, AdListSummary> _pagingController =
      PagingController(firstPageKey: 0);
  late StreamSubscription _blocListingStateSubscription;

  @override
  void initState() {
    // 仅保留一个页面请求监听
    _pagingController.addPageRequestListener((pageKey) {
      _bloc.onPageRequestSink.add(pageKey);
    });

    _blocListingStateSubscription =
        _bloc.onNewListingState.listen((listingState) {
      // 区分刷新/首次加载和分页加载逻辑
      if (listingState.nextPageKey == 0) {
        // 刷新或首次加载时直接替换数据
        _pagingController.value = PagingState(
          nextPageKey: listingState.nextPageKey,
          error: listingState.error,
          itemList: listingState.itemList,
        );
      } else {
        // 分页加载时使用appendPage追加数据,而非直接替换状态
        if (listingState.itemList != null) {
          _pagingController.appendPage(
            listingState.itemList!,
            listingState.nextPageKey,
          );
        }
      }
    });
    super.initState();
  }

  Future<void> _refreshList() async {
    // 直接调用refresh方法即可,无需setState
    _pagingController.refresh();
    print('Refresh....');
  }

  @override
  void dispose() {
    _pagingController.dispose();
    _blocListingStateSubscription.cancel();
    _bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => RefreshIndicator(
        onRefresh: _refreshList,
        child: CustomScrollView(
          slivers: <Widget>[
            PagedSliverGrid<int, AdListSummary>(
              pagingController: _pagingController,
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                childAspectRatio: 0.810,
                crossAxisCount: 2,
                mainAxisSpacing: 5,
                crossAxisSpacing: 5,
              ),
              builderDelegate: PagedChildBuilderDelegate<AdListSummary>(
                itemBuilder: (context, item, index) => AdListGridItem(
                  adlist: item,
                  press: () {
                    // 点击逻辑
                  },
                ),
              ),
            ),
          ],
        ),
      );
}

额外注意事项

  • Bloc层配合调整:确保_pagingController.refresh()触发后,AdListSliverGridBloc收到pageKey=0的请求时,会重新从服务器拉取第一页数据,同时清空之前缓存的列表数据。
  • 规范状态更新方式:除刷新/首次加载场景,分页加载时必须使用appendPage方法添加新数据,避免直接覆盖PagingState,保证插件内部状态同步正确。

内容的提问来源于stack exchange,提问作者86as

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 09:30:50