当我尝试取消 Firestore 侦听器时ProductsService().cancel()
。我收到错误:
[错误:flutter/lib/ui/ui_dart_state.cc(209)] 未处理的异常:LateInitializationError:字段“productsSubscription”尚未初始化。
没有迟到也不起作用:
StreamSubscription<QuerySnapshot>? productsSubscription;
My code:
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class ProductsService extends ChangeNotifier {
late StreamSubscription<QuerySnapshot> productsSubscription;
void cancel() => productsSubscription.cancel();
void getMenuProducts() async {
CollectionReference productsReference = FirebaseFirestore.instance.collection('products');
productsSubscription = productsReference.snapshots().listen((snapshot) => print(snapshot.docs.length));
}
}
我知道在上下文中调用 .cancel() 可以工作。
但我在带有 Riverpod 的 ChangeNotifier 中使用它。
Riverpod 的流工作正常。真正的问题是,当用户注销并新用户登录时,.listen 似乎仍然停留在旧的 firebase 用户上!并且不允许查询。 Firebase 规则使用 [cloud_firestore/permission-denied] 拒绝它们 - 当我重新启动应用程序时,查询有效。
我注意到的是,如果我能得到 .listencanceled注销时,查询在新用户登录时起作用。
因此,如果有人可以帮助我正确初始化它,或者让 Firebase 查看新用户,那将会非常有帮助。
或者有其他建议。
这似乎有效,只是感觉很脆弱,但到目前为止还可以。
服务类如下所示,其中有一个取消方法。
class ProductsServiceNotifier extends ChangeNotifier {
final FirebaseFirestore _db = FirebaseFirestore.instance;
StreamSubscription<QuerySnapshot<Object?>>? productsSubscription;
late List<ProductsModel> allProductsList = [];
bool isLoading = true;
void getShopProducts() async {
var productsRef = _db.collection('products');
productsSubscription = productsRef
.where('entity', isEqualTo: sharedPrefs.activeShopEntityCode)
.where('active', isEqualTo: true)
.snapshots()
.listen((snapshot) async {
allProductsList = snapshot.docs.map((doc) => ProductsModel.fromMap(doc)).toList();
isLoading = false;
notifyListeners();
});
}
Future cancelSub() async {
if (productsSubscription != null) await productsSubscription?.cancel();
}
}
然后在注销时调用取消,如下所示:
TextButton(
child: Text('Sign out'),
onPressed: () async {
await context.read(menuProductsNotifier).cancelSub();
FirebaseAuth.instance.signOut();
Navigator.of(context).pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false);
},
),
重要的是每次启动新列表器之前都要调用 cancel() 方法。否则,现有侦听器似乎会卡在内存中的某个位置,并导致 Firestore 规则权限被拒绝的身份验证问题。 (用例是用户可以调用启动新查询的不同实体的产品,并且需要监听它们。)
-
我的 Riverpod 提供程序中的 autodispose 在我的场景中不起作用。
-
我选择不使用 autodispose,它允许我在侦听器上调用 cancel(),当然,如果它被释放,我将无法执行此操作。
-
在 dispose 中调用 cancel 会出现错误“查找已停用小部件的祖先是不安全的。”所以这对我不起作用——我希望它能起作用。
我对任何更好的方法持开放态度。感谢您的建议!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)