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

如何避免图片下载后重复发起URL请求?Flutter代码问题求助

Flutter图片加载:解决重复请求与显示异常问题

问题场景

你尝试用alreadyDdl变量避免重复发起HTTP请求,但出现两个问题:

  1. 图片始终无法显示,只能看到占位图assets/none.png
  2. 移除alreadyDdl后,代码每15毫秒发起一次重复请求

原核心代码:

var alreadyDdl = false; 
getLogoUrl(context) async {
  if(!alreadyDdl) {
      final db = Localstore.instance;
      final data = db.collection('inputs').doc("1").get();
      var database = (await data)["content"].toString();
      var form = new DGForm("project/getwebsitelogo", {"database": database});
      var ret = await form.urlGET(context);
      ResponseObject responseObject =
      ResponseObject.fromJson(json.decode(ret.body));
      var hola = (responseObject.datas[0][0].toString());
      bandeauDuClient = hola;
      return hola;
   }
}
getLogoUrl(context).then((val) {
    setState(() => 
       logoUrl = val
    );
    alreadyDdl = true;
});

图片显示判断代码:

(logoUrl != null) ? Image.network(logoUrl): Image.asset('assets/none.png') 

问题根源

  1. alreadyDdl时机错误:你在请求完成后才设置alreadyDdl = true,但如果getLogoUrl因alreadyDdl为true直接返回null,会触发then回调把logoUrl设为null,导致占位图一直显示。
  2. build方法重复触发请求:如果getLogoUrl的调用放在build方法里,每次setState都会重新执行build,进而重复调用getLogoUrl,即使alreadyDdl为true,也会返回null覆盖已有的logoUrl。

解决方案

方案1:将请求移至initState(推荐)

initState仅在Widget初始化时执行一次,从根源避免重复请求:

class _YourWidgetState extends State<YourWidget> {
  String? logoUrl;

  @override
  void initState() {
    super.initState();
    _fetchLogo();
  }

  Future<void> _fetchLogo() async {
    try {
      // 读取本地数据
      final db = Localstore.instance;
      final data = await db.collection('inputs').doc("1").get();
      final database = data?["content"].toString();
      if (database == null) return;

      // 发起网络请求
      final form = DGForm("project/getwebsitelogo", {"database": database});
      final ret = await form.urlGET(context);
      final responseObject = ResponseObject.fromJson(json.decode(ret.body));
      final logoUrl = responseObject.datas[0][0].toString();

      // 更新UI
      setState(() {
        this.logoUrl = logoUrl;
      });
    } catch (e) {
      print("加载Logo失败: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return logoUrl != null 
        ? Image.network(logoUrl!) 
        : Image.asset('assets/none.png');
  }
}

方案2:修正状态逻辑+使用FutureBuilder

如果必须在build中处理请求,用FutureBuilder管理异步状态,同时修正请求标记的设置时机:

class _YourWidgetState extends State<YourWidget> {
  bool _isLoading = false;
  String? _cachedLogoUrl;

  Future<String?> _getLogoUrl(BuildContext context) async {
    if (_cachedLogoUrl != null) return _cachedLogoUrl;
    if (_isLoading) return null; // 防止并发请求

    _isLoading = true;
    try {
      final db = Localstore.instance;
      final data = await db.collection('inputs').doc("1").get();
      final database = data?["content"].toString();
      if (database == null) return null;

      final form = DGForm("project/getwebsitelogo", {"database": database});
      final ret = await form.urlGET(context);
      final responseObject = ResponseObject.fromJson(json.decode(ret.body));
      final logoUrl = responseObject.datas[0][0].toString();

      _cachedLogoUrl = logoUrl;
      return logoUrl;
    } catch (e) {
      print("请求失败: $e");
      return null;
    } finally {
      _isLoading = false;
    }
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<String?>(
      future: _getLogoUrl(context),
      initialData: _cachedLogoUrl,
      builder: (context, snapshot) {
        if (snapshot.hasData && snapshot.data != null) {
          return Image.network(snapshot.data!);
        } else {
          return Image.asset('assets/none.png');
        }
      },
    );
  }
}

关键优化点

  • 把请求标记(_isLoading)放在请求开始前,避免并发重复请求
  • 缓存已成功获取的logoUrl,后续直接返回缓存值
  • 使用initState或FutureBuilder管理异步请求,避免在build中直接触发请求导致的重复执行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 16:50:24