即使没有数据更改,Firestore 缓存也无法正常工作

Posted

技术标签:

【中文标题】即使没有数据更改,Firestore 缓存也无法正常工作【英文标题】:Firestore cache not working even if no data has changed 【发布时间】:2019-12-23 12:02:15 【问题描述】:

根据Alex Momo's answer,默认情况下,Firestore 将文档存储在缓存中并从那里加载,只有新文档或更改才会再次读取,但需要额外费用。

我正在使用 StreamBuilder 和 FutureBuilder 进行测试,并使用打印来显示数据的来源。

print(document.metadata.isFromCache ? "NOT FROM NETWORK" : "FROM NETWORK");

即使我使用 FutureBuilder (.getDocuments()),第一次打开应用程序时它会打印“FROM NETWORK”,第二次它会再次加载“FROM NETWORK”,并且数据库没有任何变化,所以看起来像缓存仅在应用程序真正离线时才起作用,但似乎如果有连接,它将始终从服务器加载,有人可以解释一下吗?

Source.serverAndCache 参数我认为是默认值,描述中说“导致 Firestore 尝试检索最新的(服务器检索的)快照,但回退如果无法访问服务器,则返回缓存的数据。”,我认为这意味着:您有连接吗?从服务器加载,如果不是?从缓存加载。但这并没有多大帮助,因为每次我们关闭应用程序并重新打开它都会再次从服务器加载所有文档。

FutureBuilder(
            future: Firestore.instance.collection("latest").orderBy("date", descending: true)
                .getDocuments(source: Source.serverAndCache ),
            builder: (context, snapshot) 

              if (!snapshot.hasData || snapshot.data.documents.length == null) 
                return Center(
                  child: CircularProgressIndicator(
                    valueColor: AlwaysStoppedAnimation(Colors.white),
                  ),
                );
               else if(snapshot.data.documents.length == 0) 

                return Center(
                    child: Padding(
                      padding: const EdgeInsets.only(left: 16, right: 16),
                      child: Text(
                        "Sorry but there's no wallpapers for this character yet!",
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.w300,
                        ),
                        textAlign: TextAlign.center,
                      ),
                    )
                );

               else 

                return GridView.builder(
                    itemCount: snapshot.data.documents.length,
                    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                      crossAxisCount: 2,
                      childAspectRatio: screenHeight / screenWidth * 0.4,
                      mainAxisSpacing: 1.0,
                      crossAxisSpacing: 1.0,
                    ),
                    itemBuilder: (context, index) 

                      return _buildGrid(snapshot.data.documents[index], index);

                    
                );



              
            
          )

Widget _buildGrid(DocumentSnapshot document, int index) 

      print(document.metadata.isFromCache ? "NOT FROM NETWORK" : "FROM NETWORK");

      return GestureDetector(
        child: Hero(
          tag: index,
          child: CachedNetworkImage(
            imageUrl: document['url'],
            errorWidget: (context, url, error) => Icon(Icons.error_outline),
            fit: BoxFit.fill,
            filterQuality: FilterQuality.low,

          ),

        ),
        onTap: () 
          Navigator.of(context).push(
              MaterialPageRoute(
                  builder: (context) => DetailScreen(document['url']))
          );
        ,
      );
    

【问题讨论】:

这是正确的行为 如果您离线,将创建一个本地副本,并且在您离线时完成的任何数据库write 将在您再次在线时同步。但随后仍会从服务器检索数据 【参考方案1】:

Peter 的 cmets 是正确的。每当您致电.getDocuments(source: Source.serverAndCache ) 时,Firestore 都需要检查服务器以查看数据是否被修改。由于这需要服务器读取文档,因此您需要为这些读取付费。

如果您想强制 Firestore 从其本地缓存中读取,请使用 .getDocuments(source: Source.Cache)。这意味着您会冒着显示陈旧数据的风险,但这是您必须做出的权衡。

我通常建议使用onSnapshot 侦听器,因为它们更适合仅将更改从服务器发送到客户端。

也可以看看:

firestore how to check if new documents added matching a particular query What relationship between firestore snapshotlistener's lifecycle and pricing?

【讨论】:

以上是关于即使没有数据更改,Firestore 缓存也无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

即使从缓存中获取数据,Firestore 数据库读取计数也会增加

Firestore - 使用缓存直到在线内容更新

如何使用本地缓存并仅使用 Firestore 更新更改的文档?

当我开始在 Firestore 中收听单个文档时,我是不是需要支付一次阅读费用,即使该文档没有更改?

即使我禁用了持久性,Firestore 仍在从缓存中检索文档

为啥即使禁用缓存,服务器也会忽略代码文件中的更改?