Flutter更新Firebase Firestore数组时报lost connection错误致模拟器崩溃
问题根因
触发更新后模拟器崩溃报连接丢失,核心是4个代码逻辑错误引发内存溢出、死循环,和Firestore服务本身无关:
- 全局定义的
listTest没有清空逻辑,每次点击列表项都会执行listTest.addAll(data['allItems']),多次点击后列表会无限累加重复数据,内存占用持续上涨直到进程崩溃 myTest写入方法的数据结构写错:把整个listTest数组又套了一层方括号,存到Firestore的allItems字段变成了二维数组[[{item1}, {item2}...]],和代码预期的一维对象数组结构完全不匹配,后续读取时会报类型错误- 你用
StreamBuilder实时监听目标文档,每次写入Firestore都会触发stream推送新快照,但是点击逻辑里没有加重复提交拦截,会触发「写入→刷新→自动触发写入→再次刷新」的死循环,短时间大量请求直接打崩模拟器连接 set写入方法注释掉了SetOptions(merge:true)配置,默认会全量覆盖整个文档,没传入的字段会被直接删除,很容易丢数据
分步修复方案
1. 修正状态变量定义,避免全局污染
删掉全局声明的List listTest =[];,把列表变量放到_DetailScreen_CheckList_V3State类内部作为页面私有状态,不要用全局变量存单页面状态,避免多页面实例互相干扰。
另外不要自己在State类里写构造函数传docID,Flutter的State类直接通过widget.docID就能拿到组件传入的参数,自定义构造传参很容易出现状态不同步问题。
class _DetailScreen_CheckList_V3State extends State<DetailScreen_CheckList_V3> { // 删掉自定义的docID变量和对应的构造函数,统一用widget.docID拿参数 List<Map<String, dynamic>> listTest = []; // 加更新锁,防止重复提交触发死循环 bool isUpdating = false;
2. 修复列表点击逻辑,避免无限累加
点击逻辑里每次给临时列表赋值前先清空旧数据,同时用更新锁做拦截,上一次写入没完成的时候不允许重复触发操作:
onTap: () async { // 重复点击直接拦截 if(isUpdating) return; isUpdating = true; String checked = data['allItems'][index]['itemChecked']; String myListName = data['listName']; // 核心修复:每次赋值前清空列表,避免多次addAll导致数据无限累加 listTest.clear(); listTest.addAll(List<Map<String,dynamic>>.from(data['allItems'])); setState(() { checked = checked == 'Yes' ? 'No' : 'Yes'; listTest[index]['itemChecked'] = checked; }); // 等写入完成后再放开锁 await myTest(myListName); isUpdating = false; }
3. 修正Firestore写入逻辑
去掉allItems字段外层多余的数组套嵌,打开merge配置避免全量覆盖文档:
Future myTest(currentListName) async { await FirebaseFirestore.instance .collection('Users') .doc(FirebaseAuth.instance.currentUser.uid) .collection('lists') .doc(widget.docID) .set( { 'listName': currentListName, // 核心修复:listTest本身就是数组,不要再套一层[],否则会变成二维数组 "allItems": listTest, }, // 打开merge配置,只更新传入的字段,不会覆盖文档里其他未传的字段 SetOptions(merge: true), ); }
4. 其他必改的小问题
AddObjectItemToArray方法不要包在setState里调用,setState只用来做同步的页面状态更新,异步Firestore操作直接触发即可,stream会自动推送新数据刷新页面,不需要手动调用setState- 删掉
MyBody外层套的SingleChildScrollView,ListView本身自带滚动能力,两层滚动组件嵌套会出现滚动冲突、滑动卡顿问题 - 不要把组件构建逻辑写在State类里当普通方法传context,抽成独立的StatelessWidget能大幅减少不必要的组件重建,提升页面性能
性能优化方案
如果只是更新数组内单个元素的属性,不需要每次把整个数组读出来改完再全量覆盖,Firestore支持直接通过数组下标更新指定字段,连临时列表都不需要创建,性能更高也不会出现数据结构写错、累加的问题:
// 直接更新指定下标的字段,无需拉取全量数组 FirebaseFirestore.instance .collection('Users') .doc(FirebaseAuth.instance.currentUser.uid) .collection('lists') .doc(widget.docID) .update({"allItems.$index.itemChecked": checked == 'Yes' ? 'No' : 'Yes'});
内容的提问来源于stack exchange,提问作者Laurent Thomas
相关产品推荐
相关产品推荐

