Flutter使用Image.network加载图片首次进入报Valid Value range is empty:0错误,重载后正常
问题根因
- 你定义的
galleryLoad是异步方法,Dart执行initState逻辑时不会等待异步方法执行完毕,会直接触发首次页面构建 - 首次构建时网络请求尚未返回结果,
images还是空数组,直接访问images[0]自然会抛出「有效取值范围为空,索引0不存在」的错误 - 重载应用时此前的网络请求已经执行完成,
images已经写入了返回的图片数据,所以不会触发报错
修复步骤
注意两个核心问题:
- 异步请求完成后需要调用
setState通知Flutter重新渲染页面 - 页面构建时要先判断
images数组是否有数据,再渲染对应组件
方案1:手动维护加载状态(改动最小)
首先在State类中初始化images为空数组:
List images = [];
修改galleryLoad方法,赋值后调用setState:
galleryLoad(String uid) async { EasyLoading.show(status: "Fetching Images"); var url = '${serverPath}restaurantsGalleryImages'; Map<String, String> requestHeaders = { 'Content-type': 'application/json', 'Accept': "application/json", 'Authorization': "Bearer $uid", }; var body = json.encoder.convert({}); var response = await http .post(Uri.parse(url), headers: requestHeaders, body: body) .timeout(const Duration(seconds: 30)); dprint('Response status: ${response.statusCode}'); if (response.statusCode == 200) { EasyLoading.showSuccess("Images Fetched"); var jsonResult = json.decode(response.body); // 赋值后调用setState触发页面重绘 setState(() { images = jsonResult['images']; }); print(images.length); } else { print("statusCode=${response.statusCode}"); } }
修改build方法,增加数据判断逻辑:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Gallery",style: TextStyle(color: Colors.black),), ), body: images.isEmpty // 数据未加载完成时显示加载占位 ? Center(child: CircularProgressIndicator()) : Container( height: 400, width: 400, child: Image.network("https://nearxt.com/admin/public/${images[0]['image'].toString()}"), ), ); }
方案2:用FutureBuilder管理异步逻辑(更规范)
修改galleryLoad为带返回值的Future方法:
Future<List> galleryLoad(String uid) async { EasyLoading.show(status: "Fetching Images"); var url = '${serverPath}restaurantsGalleryImages'; Map<String, String> requestHeaders = { 'Content-type': 'application/json', 'Accept': "application/json", 'Authorization': "Bearer $uid", }; var body = json.encoder.convert({}); var response = await http .post(Uri.parse(url), headers: requestHeaders, body: body) .timeout(const Duration(seconds: 30)); dprint('Response status: ${response.statusCode}'); if (response.statusCode == 200) { EasyLoading.showSuccess("Images Fetched"); var jsonResult = json.decode(response.body); return jsonResult['images']; } else { print("statusCode=${response.statusCode}"); return []; } }
修改build方法,用FutureBuilder包裹渲染逻辑:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Gallery",style: TextStyle(color: Colors.black),), ), body: FutureBuilder<List>( future: galleryLoad(account.token), builder: (context, snapshot) { // 加载中显示占位 if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } // 加载失败/无数据显示占位 if (snapshot.hasError || !snapshot.hasData || snapshot.data!.isEmpty) { return Center(child: Text("暂无图片数据")); } final images = snapshot.data!; return Container( height: 400, width: 400, child: Image.network("https://nearxt.com/admin/public/${images[0]['image'].toString()}"), ); }, ), ); }
如果你要配合GridView.builder使用,直接把itemCount设置为images.length即可,也能避免索引越界问题。
内容的提问来源于stack exchange,提问作者ARPIT JAISWAL IET Student
相关产品推荐
相关产品推荐

