Flutter中Firestore的collectionStream流isEmpty判断结果异常问题
问题根因
你遇到的逻辑错误核心是对Stream.isEmpty的属性理解有误:Stream.isEmpty返回的bool值代表的是整个流从被监听直到关闭的整个生命周期内,是否没有发出过任何数据事件,和事件本身的内容无关。
而Firebase Firestore的集合流是持续监听流,只要你发起监听,它一定会立刻返回一次当前集合的快照数据:哪怕集合里没有任何文档,也会返回一个空的List<Shop>作为第一个数据事件。也就是说不管你的集合有没有数据,await db.shopStream().isEmpty永远会返回false,自然永远进入else分支。
另外从使用场景来说,你只是点击按钮时做一次一次性的状态判断,完全没必要使用持续监听的Stream,反而会造成不必要的性能损耗。
解决方案
方案1(推荐):新增一次性查询接口
给你的Database类新增一个专门判断店铺集合是否为空的一次性查询方法,用limit(1)优化查询性能,不需要拉取全部文档:
Future<bool> isShopCollectionEmpty() async { final querySnapshot = await _service .collection(APIPath.shops(uid)) .limit(1) .get(); return querySnapshot.docs.isEmpty; }
然后修改你的跳转逻辑调用这个接口:
Future<void> _shopActivatePage (BuildContext context) async{ final db = Provider.of<Database>(context, listen: false); if (await db.isShopCollectionEmpty()) { Navigator.of(context).push(MaterialPageRoute<void>( builder: (context) => const ShopActivatePage(), fullscreenDialog: true, )); } else{ Navigator.of(context).push(MaterialPageRoute<void>( builder: (context) => const EmptyContent( title: 'Shop activated', message: 'Your shop has been set up', ), fullscreenDialog: true, )); } }
注意:原来的
async void方法最好改成Future<void>,方便后续加错误捕获、加载状态处理,避免未捕获的异步异常。
方案2(兼容现有流实现)
如果你不想改Database类的代码,可以直接取流的第一个事件,判断返回的列表本身是否为空:
// 把原来的if判断改成下面的写法 if ((await db.shopStream().first).isEmpty) { // 跳转激活页逻辑 }
这种方法不推荐,因为会临时创建一个流监听,消耗多余的资源,只适合临时调试用。
内容的提问来源于stack exchange,提问作者Derra
相关产品推荐
相关产品推荐

