Flutter项目Firestore无法正确保存imageUrl,首项为null后续错位求助
问题根因
你出现imageUrl错位的核心原因是异步任务的执行顺序和变量取值时机错误:
- 点击Save按钮时你先提前读取了全局变量
itemImageUrl的值赋值给局部变量,这时候图片上传任务还没执行,拿到的是上一次上传完成后的残留值(第一次操作时全局变量初始为null,所以第一个条目imageUrl是null) - 全局变量
itemImageUrl是在uploadItemOfShop的上传完成回调中才会被赋值新值,等你第二次新增条目时,拿到的itemImageUrl是上一次上传的结果,就出现了错位的问题 - 全局变量存储单条目的imageUrl没有做重置,也会导致值的复用错乱
修复方案
步骤1:修改uploadItemOfShop方法,直接返回上传后的图片URL,不再依赖全局变量存储
Future<String?> uploadItemOfShop(BuildContext context) async { Reference ref = storage.ref().child( "${this.widget.nameShop}'s ${_itemName.text} Price ${_price.text}" + DateTime.now().toString()); // 原有判断_image.toString() == ''逻辑错误,直接判断是否为null即可 if (_image == null) { Flushbar( title: "Menu Item Image is empty", message: "Please Add some Image first", backgroundColor: Colors.red, boxShadows: [ BoxShadow( color: Colors.red[800], offset: Offset(0.0, 2.0), blurRadius: 3.0, ) ], duration: Duration(seconds: 3), )..show(context); return null; } else { setState(() { isLoadingNow=true; }); try { UploadTask uploadTask = ref.putFile(_image); final res = await uploadTask; final itemImageUrl = await res.ref.getDownloadURL(); setState(() { isLoadingNow=false; _image = null; // 直接清空即可,不需要额外声明_image2变量 }); return itemImageUrl; } catch(e) { setState(() { isLoadingNow=false; }); Fluttertoast.showToast(msg: '图片上传失败,请重试'); return null; } } }
步骤2:修改Save按钮的点击逻辑,等待上传完成拿到URL后再构建条目
onPressed: () async { if(_image !=null){ // 提前保存当前表单的所有值,避免上传过程中用户修改表单导致数据不一致 int price=int.parse(_price.text); String itemName=_itemName.text; String itemDesc=_desc.text; String categoryO=this.categoryToSave; bool itemCondition = condition; bool itemIsPopular = this.isPopular; // 等待上传完成拿到当前条目的图片URL final imageUrl = await uploadItemOfShop(context); if(imageUrl == null) return; // 上传失败直接终止后续逻辑 String idO=getRandomString(3); var item = { 'itemName': itemName, 'itemPrice': price, 'itemDesc': itemDesc, 'category': categoryO, 'condition': itemCondition, 'imageUrl': imageUrl, 'isPopular': itemIsPopular, 'id': idO, }; setState(() { itemo.add(item); _showDg = false; }); _price.clear(); _desc.clear(); _itemName.clear(); }else{ Fluttertoast.showToast(msg: '请先选择图片'); } }
额外优化建议
- 可删除全局的
itemImageUrl变量,避免后续误用 - 表单的开关状态(condition、isPopular)建议和文本字段一样,每次保存前提前存局部变量,避免上传过程中用户修改开关导致数据和提交的内容不一致
- 尽量用async/await代替链式then调用,逻辑更清晰,不容易出现时序错误
内容的提问来源于stack exchange,提问作者Bill_The_Coder
相关产品推荐
相关产品推荐

