Flutter开发:如何预加载从JSON解析获取的网络图片?
Flutter预加载本地JSON解析的网络图片问题解决方法
问题原因
你之前的方案失效,核心原因是readJson()是异步方法,initState()会直接执行后续代码,不会等待JSON解析完成。这时候调用precacheImage时,_items还是空列表,根本拿不到图片URL,自然无法预加载。
解决步骤
- 等待
readJson()执行完成,确保_items已经填充数据 - 在Widget完成第一帧绘制后执行预加载,避免
context使用异常 - 遍历
_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
相关产品推荐
相关产品推荐

