如何在Hive中监听自定义键变化及实现类似Firestore快照的全量数据监听
问题1:监听指定key无回调的解决方法
错误原因
- 方法声明返回
Stream<BoxEvent>但实际没有返回Stream对象,且内部创建的监听订阅没有被持有,会被系统GC回收导致回调失效 - 如果你是直接修改已取出的
CartItemModel的属性后没有重新put回box,Hive无法感知对象内部属性变更,不会触发watch回调 - 需确认操作的box名称为同一个
cart,且监听的key和实际存储的cartItemId完全匹配
正确实现代码
// 写法1:返回Stream供上层持有订阅 Stream<BoxEvent> listenToLocalCartItem(String cartItemId) { final box = Hive.box('cart'); // 直接返回watch的Stream,不要在当前方法内直接listen return box.watch(key: cartItemId); } // 上层使用示例(Bloc场景) late StreamSubscription _cartItemSub; void initCartListener(String cartItemId) { // 首次初始化先获取当前值渲染 final currentItem = Hive.box('cart').get(cartItemId); if (currentItem == null || currentItem.numberOfItems <= 0) { emit(AddToCartState.showAddButton()); } else { emit(AddToCartState.showCartValue(currentItem.numberOfItems)); } // 订阅后续变动 _cartItemSub = listenToLocalCartItem(cartItemId).listen((event) { if (event.value == null) { emit(AddToCartState.showAddButton()); return; } CartItemModel cartItem = event.value as CartItemModel; if (cartItem.numberOfItems > 0) { emit(AddToCartState.showCartValue(cartItem.numberOfItems)); } else { emit(AddToCartState.showAddButton()); } }); } // Bloc关闭时取消订阅避免内存泄漏 @override Future<void> close() { _cartItemSub.cancel(); return super.close(); }
注意:修改购物车数据时必须重新put到box,仅修改对象属性不会触发监听:
// 错误写法 var item = box.get('item1'); item.numberOfItems = 2; // 正确写法 var item = box.get('item1'); item.numberOfItems = 2; box.put('item1', item);
问题2:监听整个box所有变动的解决方法
错误原因
Hive.openBox('cart').asStream()只会在box打开完成时触发一次,不会监听后续的box数据变动。
正确实现代码
调用box的watch()方法不传key参数,即可监听box内所有key的增删改操作,实现类似Firestore快照的效果:
// 监听整个box所有变动 Stream<BoxEvent> listenToWholeCartBox() { final box = Hive.box('cart'); return box.watch(); } // 上层使用示例 late StreamSubscription _wholeCartSub; void initWholeCartListener() { final box = Hive.box('cart'); // 首次打开先获取当前全量数据初始化 _cartStatusProvider.cartItems = box.values.toList().cast<CartItemModel>(); // 订阅后续变动,每次变动更新全量数据 _wholeCartSub = listenToWholeCartBox().listen((_) { _cartStatusProvider.cartItems = box.values.toList().cast<CartItemModel>(); }); } // 页面销毁/逻辑卸载时取消订阅 @override void dispose() { _wholeCartSub.cancel(); super.dispose(); }
内容的提问来源于stack exchange,提问作者Omar Abdelazeem
相关产品推荐
相关产品推荐

