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

如何保存FutureProvider数据,避免反复重建引发API请求次数超限?

问题根源

你将FutureProvider放在ListView.builder的itemBuilder回调内,每次条目滚出屏幕再滚回时,条目会重新构建,create回调就会重新执行触发新的API请求。你仅开启了ListView的addAutomaticKeepAlives配置,但条目本身没有实现保活逻辑,且每次构建都会生成新的FutureProvider实例,原有状态直接丢失,请求自然重复触发。

修复方案

下面按优先级给可落地的修复方案:

方案1:新增请求缓存层(最推荐,性能最优)

不要在条目构建时触发请求,提前在页面上层统一管理所有请求的缓存,同一个index的请求仅触发一次:

// 首先在当前页面的State中定义缓存容器
Map<int, List<dynamic>> _fireIceCountCache = {};
// 封装带缓存的请求方法
Future<List<dynamic>> _getCachedFireIceCount(int index, List places) async {
  if (_fireIceCountCache.containsKey(index)) {
    return _fireIceCountCache[index]!;
  }
  final result = await getFireIceCount(index, places);
  _fireIceCountCache[index] = result;
  return result;
}

之后把itemBuilder里create回调的调用替换成_getCachedFireIceCount(index, places)即可,就算条目重建,同一个index的请求只会执行一次。

方案2:实现条目保活

如果你的条目数量不多(少于20个),可以直接保活所有条目,避免重建:

  1. 把条目逻辑单独抽成一个StatefulWidget
  2. 给Widget的State混入AutomaticKeepAliveClientMixin,配置wantKeepAlive返回true
    示例代码:
class PlaceItem extends StatefulWidget {
  final int index;
  final List places;
  const PlaceItem({super.key, required this.index, required this.places});

  @override
  State<PlaceItem> createState() => _PlaceItemState();
}

class _PlaceItemState extends State<PlaceItem> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context); // 必须调用
    return FutureProvider<List<dynamic>?>(
      initialData: null,
      create: (context) => getFireIceCount(widget.index, widget.places),
      child: Consumer<List<dynamic>?>(
        builder: (context, fireIceCount, child) {
          if (fireIceCount == null) {
            return const Center(child: CircularProgressIndicator(color: Colors.red));
          }
          if (fireIceCount.isNotEmpty) {
            return PlacesImageViewer();
          }
          return const Center(child: CircularProgressIndicator(color: Colors.cyan));
        },
      ),
    );
  }
}

之后ListView的itemBuilder直接返回PlaceItem(index: index, places: places)即可。

方案3:预创建Future缓存

在页面初始化阶段就把所有index对应的Future提前创建好存在List中,itemBuilder的create回调直接返回对应index的Future,同一个Future只会执行一次:

// 在State中定义Future缓存列表
late List<Future<List<dynamic>>> _fireIceCountFutures;

@override
void initState() {
  super.initState();
  // 页面初始化时一次性创建所有Future
  _fireIceCountFutures = List.generate(places.length, (index) => getFireIceCount(index, places));
}

之后itemBuilder里create回调返回_fireIceCountFutures[index]即可。

内容的提问来源于stack exchange,提问作者Arslan Kaleem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 09:00:00