提问者:小点点

离线问题与Firebase


我将我的一个应用程序转换为新的Fi恢复。我正在做一些事情,例如单击按钮保存文档,然后在on成功侦听器中,转到不同的活动。

我还使用Fi恢复保存操作返回任务的事实,使用Task. whenAll将任务分组在一起:

val allTasks = Tasks.whenAll(
       createSupporter(supporter),,
       setStreetLookup(makeStreetKey(supporter.street_name)),
       updateCircleChartForUser(statusChange, createMode = true), 
       updateStatusCountForUser(statusChange))

      allTasks.addOnSuccessListener(this@SignUpActivity, successListener)
      allTasks.addOnFailureListener(this@SignUpActivity, onFailureListener)

最后,我从成功的保存中获取文档ID并将其存储在首选项或本地数据库中以供以后使用(在onChoessListener中)

这一切都很好。直到失去网络连接。然后一切都分崩离析,因为任务永远不会完成,on成功/onFailure/on完成侦听器永远不会被调用。所以应用程序只是挂起。

我正在通过在每次保存之前检查网络可用性来解决这个问题,然后通过创建没有任何侦听器的任务来解决这个问题。我还使用UUID生成器在本地生成文档ID。

BTW,这不是应用程序与旧火力基地的工作方式。在这种情况下,离线时一切都运行良好,每当应用程序上线时,我都会看到文档同步。

我对Fi的变通方法似乎是一个糟糕的黑客攻击。有人想出更好的解决方案了吗?

在没有连接时未调用插入/删除文档回调时,请参阅相关的Fi惋惜数据库addOnCompleteListener未使用云fi恢复离线调用


共3个答案

匿名用户

云图为我们提供了处理离线数据的功能,但是你需要使用“快照”(QuerySnapshot,DocumentSnapshot)来处理这种情况,不幸的是它没有很好地记录下来。这是一些使用快照处理案例的代码示例(我使用静态编程语言Android):

更新数据:

db.collection("members").document(id)
  .addSnapshotListener(object : EventListener<DocumentSnapshot> {
      override fun onEvent(snapshot: DocumentSnapshot?,
                           e: FirebaseFirestoreException?) {
          if (e != null) {
              Log.w(ContentValues.TAG, "Listen error", e)
              err_msg.text = e.message
              err_msg.visibility = View.VISIBLE;
              return
          }
          snapshot?.reference?.update(data)

      }
  })

添加数据:

db.collection("members").document()
 .addSnapshotListener(object : EventListener<DocumentSnapshot> {
     override fun onEvent(snapshot: DocumentSnapshot?,
                          e: FirebaseFirestoreException?) {
         if (e != null) {
             Log.w(ContentValues.TAG, "Listen error", e)
             err_msg.text = e.message
             err_msg.visibility = View.VISIBLE;
             return
         }
         snapshot?.reference?.set(data)

     }
 })

删除数据:

db.collection("members").document(list_member[position].id)
   .addSnapshotListener(object : EventListener<DocumentSnapshot> {
       override fun onEvent(snapshot: DocumentSnapshot?,
                            e: FirebaseFirestoreException?) {
           if (e != null) {
               Log.w(ContentValues.TAG, "Listen error", e)
               return
           }
           snapshot?.reference?.delete()
       }
   })

你可以在这里看到代码示例:https://github.com/sabithuraira/KotlinFirestore和博客文章http://blog.farifam.com/2017/11/28/android-kotlin-management-offline-firestore-data-automatically-sync-it/

匿名用户

当网络连接丢失时(用户设备上没有网络连接),on成功()onFailure()都不会触发。这种行为是有道理的,因为只有当数据已在Firebase服务器上提交(或拒绝)时,任务才会被视为完成。因此,只有当任务成功完成时,on成功()才会触发。

无需在每次保存之前检查网络可用性。有一个解决方法可以轻松帮助您查看Fi恢复客户端是否确实无法连接到Firebase服务器,这是通过启用调试日志记录

FirebaseFirestore.setLoggingEnabled(true);

一旦向后端实际提交数据,将数据写入Fi恢复数据库的操作被定义为信号完成。因此,这按预期工作:离线时,它们不会发出完成信号。

请注意,即使您不等待删除任务完成,Fi恢复客户端内部也保证您可以读取自己的写入。Fi恢复客户端旨在在没有互联网连接的情况下继续正常运行。因此,在没有互联网连接的情况下写入/删除数据库是(按设计)可能的,并且永远不会产生错误。

匿名用户

我在http://blog.farifam.com发现了如何使用信息来完成它。基本上,你必须使用SnapshotListeners而不是On成功监听器来进行离线工作。此外,你不能使用谷歌的任务,因为它们不会离线竞争。

相反(因为任务基本上是Promises),我使用了静态编程语言KoWannes库,它可以将侦听器附加到Promises。一个缺点是,您必须配置KoWannes以允许对Promise进行多次解析,因为事件侦听器可以调用两次(一次是在数据添加到本地缓存时,一次是在同步到服务器时)。

这是一个示例代码片段,带有成功/失败侦听器,可在线和离线运行。

val deferred = deferred<DocumentSnapshot, Exception>() // create a deferred, which holds a promise
// add listeners
deferred.promise.success { Log.v(TAG, "Success! docid=" + it.id) }
deferred.promise.fail { Log.v(TAG, "Sorry, no workie.") }

val executor: Executor = Executors.newSingleThreadExecutor()
val docRef = FF.getInstance().collection("mydata").document("12345")
val data = mapOf("mykey" to "some string")

docRef.addSnapshotListener(executor, EventListener<DocumentSnapshot> { snap: DocumentSnapshot?, e: FirebaseFirestoreException? ->
    val result = if (e == null) Result.of(snap) else Result.error(e)
    result.failure {
        deferred.reject(it) // reject promise, will fire listener
    }
    result.success { snapshot ->
        snapshot.reference.set(data)
        deferred.resolve(snapshot) // resolve promise, will fire listener
    }
})