Firestore 单文档快照流未更新

Posted

技术标签:

【中文标题】Firestore 单文档快照流未更新【英文标题】:Firestore single document snapshot stream not updating 【发布时间】:2021-09-02 12:20:37 【问题描述】:

我的 Flutter 应用程序需要监听特定 Firestore 文档中的任何更改。

这个过程非常简单,可以在各种解决方案中找到:

    ***: flutter-firestore-how-to-listen-for-changes-to-one-document ***:can-i-listen-to-a-single-document-in-firestore-with-a-streambuilder ***:using-stream-building-with-a-specific-firestore-document ***: how-to-get-a-specific-firestore-document-with-a-streambuilder 中等: how-to-get-data-from-firestore-and-show-it-on-flutterbuilder-or-streambuilder-e05

这些都是使用StreamStreamBuilder 并监听任何变化的解决方案。

通常使用这种方法:

Stream<UserModel?> getFirestoreUser(String uid) 
  return FirebaseFirestore.instance.collection('users').doc(uid).snapshots().map((event) => event.data()).map((event) => event == null ? null : UserModel.fromJson(event));

地点:

UserModel 有一个 fromJson(Map&lt;String, dynamic&gt;) 工厂构造函数 并且存在文档 ID 为 uidusers 集合。

Stream 返回一个Stream&lt;UserModel?&gt;,以后可以由Provider.of&lt;UserModel?&gt;(context)StreamBuider&lt;UserModel?&gt; 使用


问题:

TL;DR - 在更新 Firestore().getCurrentUser(uid) 流后(直接或手动使用 Firestore 模拟器并更改文档值),下面的 StreamBuilder&lt;UserModel?&gt; 不会更新。

在应用程序生命周期的所有时间点(无论是否经过身份验证),流始终返回 null(但是使用 .first 手动调用流会返回用户内容,但 .last 只是挂起)。有关详细信息,请参见下文。

链接到github project。

开始:

    将您自己的gooogle-services.json 文件放入android/app 文件夹中 将com.flutterprojects.myapp 的所有引用更改为$your google-services.json package name 使用本地模拟器更新 Firestore 更改

更多详情:

我的问题使用了类似的方法,但 Stream 没有返回任何内容。我的 Flutter 小部件 LoggedIn()FirebaseAuth.instance.currentUser 有效(即不为空)时使用

class LoggedIn extends StatelessWidget
  @override
  Widget build(BuildContext context) 
    // TODO: implement build
    return StreamBuilder<UserModel?>(
      builder: (context, snapshot) 
        print("Checking UserModel from stream provider");
        if (snapshot.data == null) 
          print("UserModel is null");
          return UiLogin();
        

        print("UserModel is NOT null");
        return UiHome();
      ,
    );
  

验证成功后,文本Checking UserModel from stream provider 会打印到控制台,然后是UserModel is nullUserModel is NOT null 绝不会显示。

成功验证后(即用户注册和文档更新),我有一个按钮,我手动调用流并获取第一项:

var currentUser = Firestore().getCurrentUser(FirebaseAuth.instance.currentUser!.uid);
var first = await currentUser.first;
print(first);

根据新增的用户信息返回UserModel

运行以下代码时,在.last处停止执行,没有错误,没有崩溃,没有应用退出,只是停止执行。

var currentUser = Firestore().getCurrentUser(FirebaseAuth.instance.currentUser!.uid);
var last = await currentUser.last;
print(last);

但是

添加以下内容时,所有更改都会更新并打印到控制台

Firestore().getCurrentUser(currentUid).listen((data) 
    print("Firestore Data Changed");
    print("Firestore change value: $data");
);

这意味着StreamBuilder&lt;UserModel?&gt; 无法正常工作,因为Stream&lt;UserModel&gt; 事件执行listen() 更改并确认这些更改,但StreamBuilder&lt;UserModel?&gt; 更改不会受到影响并始终返回null

我是不是做错了什么?

【问题讨论】:

您是否在 StreamBuilder 中添加了 stream: 参数? 【参考方案1】:

试试if (snapshot.hasData) print("UserModel is null"); return UiLogin();

【讨论】:

snapshot.hasData 是一个美化的 snapshot.data != null 检查我已经在做的检查,请参阅 api.flutter.dev/flutter/widgets/AsyncSnapshot/hasData.html。这有什么帮助?【参考方案2】:

这对我有用。也许连接状态是缺失的。

StreamBuilder(
        stream: FirebaseFirestore.instance
            .collection('users')
            .doc(widget.uid)
            .collection('contacts')
            .doc(widget.client)
            .collection('messages')
            .orderBy('timestamp', descending: true)
            .snapshots(),
        builder: (context, snapshot) 
          if (snapshot.hasError)
            return Expanded(
              child: Center(child: Text('Problem Getting Your Messages')),
            );

          switch (snapshot.connectionState) 
            case ConnectionState.none:
              return Text('waiting');
            case ConnectionState.waiting:
              return Center(child: Text('Waiting'));
            case ConnectionState.active:
              var snap;
              print('active');
              if (snapshot.data != null) 
                snap = snapshot.data;
              
              return Expanded(
                child: ListView(
                  ...
              );

            case ConnectionState.done:
              print('done');
              return Text('Lost Connection');
          

          return Text('NOPE');
        ,
      ),

【讨论】:

以上是关于Firestore 单文档快照流未更新的主要内容,如果未能解决你的问题,请参考以下文章

添加新文档时,kotlin firestore 未更新我的 android 应用程序

如何为使用 Firestore 文档快照的模型编写测试

Google Firestore 是缓存文档和集合还是总是请求新的?

在 Flutter 中捕获云 Firestore 文档快照错误

区分 Firestore 中的第一次查询快照和更改侦听器

当大量文档从 Firestore 快照到达时,如何不让 ReactJS 应用程序冻结?