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

Flutter开发:如何预加载从JSON解析获取的网络图片?

Flutter预加载本地JSON解析的网络图片问题解决方法

问题原因

你之前的方案失效,核心原因是readJson()是异步方法,initState()会直接执行后续代码,不会等待JSON解析完成。这时候调用precacheImage时,_items还是空列表,根本拿不到图片URL,自然无法预加载。

解决步骤

  1. 等待readJson()执行完成,确保_items已经填充数据
  2. 在Widget完成第一帧绘制后执行预加载,避免context使用异常
  3. 遍历_items中的图片URL,批量调用precacheImage

修改后的完整代码

class _KillerRouteState extends State<KillerRoute> {
  List _items = [];

  // Fetch content from the json file
  Future<void> readJson() async {
    final String response = await rootBundle.loadString('assets/dbdKillers.json');
    final data = json.decode(response);
    setState(() {
      _items = data["killers"];
    });
  }

  // 批量预加载图片
  void _precacheImages(BuildContext context) {
    for (var killer in _items) {
      final portraitUrl = killer["portrait"];
      if (portraitUrl != null && portraitUrl.isNotEmpty) {
        precacheImage(NetworkImage(portraitUrl), context);
      }
    }
  }

  @override
  void initState() {
    super.initState();
    // 等待JSON解析完成后执行预加载
    readJson().then((_) {
      if (mounted && _items.isNotEmpty) {
        // 确保Widget已完成第一帧绘制,避免context问题
        WidgetsBinding.instance.addPostFrameCallback((_) {
          _precacheImages(context);
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
      appBar: topAppBar,
      bottomNavigationBar: Container(
        height: 55.0,
        child: BottomAppBar(
          color: Color.fromRGBO(58, 66, 86, 1.0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              IconButton(
                  icon: Icon(Icons.home, color: Colors.white),
                  onPressed: () {
                    Navigator.of(context).push(_AnimatedNavigation(Main()));
                  }
              ),
            ],
          ),
        ),
      ),
      body: Center(
        child: Column(
          children: [
            _items.isNotEmpty
                ? Expanded(
              child: GridView.builder(
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                ),
                itemCount: _items.length,
                itemBuilder: (context, index) {
                  return Column(
                    children: [
                      RawMaterialButton(
                        child: Image(
                          image: NetworkImage(_items[index]["portrait"]),
                          height: 190,
                          width: 150,
                        ),
                        onPressed: () {
                          Navigator.push(context, _AnimatedNavigation(SpecificCharacterRoute(
                              _items[index]["name"], _items[index]["full_name"], _items[index]["shop_background"], _items[index]["overview"],
                              _items[index]["difficulty"], "images/dbdkillerlogo.png")
                          )
                          );
                        },
                      ),
                    ],
                  );
                },
              ),
            )
                : Container(),
          ],
        ),
      ),
    );
  }
}

额外说明

  • 使用mounted判断是为了避免Widget已经被销毁时,异步操作还在执行导致的异常
  • addPostFrameCallback确保在Widget完成第一帧绘制后再调用precacheImage,此时context是安全可用的
  • 如果需要更精细的预加载控制(比如只预加载当前屏幕可见的图片),可以在GridView的itemBuilder中对每个图片单独调用precacheImage,但这属于懒加载范畴,而非全局预加载

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 08:01:02