取消 ChangeNotifier 内的 Firebase 监听器

2024-04-01

当我尝试取消 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(使用前将#替换为@)

取消 ChangeNotifier 内的 Firebase 监听器 的相关文章