在Android Worker中使用Firebase事件监听器

4
我正在尝试使用Android WorkManager中的Worker,并带有Firebase数据库引用的事件侦听器。如果应用程序在前台/后台中,它可以正常工作。但是一旦我关闭应用程序并运行工作程序,则事件侦听器不会触发。据我所知,日志中没有与此相关的错误消息。
这是一个示例代码:
class FirebaseWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
    val firebaseDatabaseRef = FirebaseDatabase.getInstance().reference
    firebaseDatabaseRef.addListenerForSingleValueEvent(object : ValueEventListener {
        override fun onDataChange(dataSnapshot: DataSnapshot) {
            // Handle DataSnapshot
        }

        override fun onCancelled(databaseError: DatabaseError) {
            // Handle DatabaseError
        }
    })

    return Result.SUCCESS
  }
}

请告诉我有什么办法可以在应用关闭时后台获取和处理Firebase实时数据库的数据。


你能否添加清单声明?你的服务是否使用了android:process? - Anis BEN NSIR
@AnisBENNSIR 在 AndroidManifest 文件中没有关于 worker 的唯一声明。Android WorkManager 根据 API 级别自动选择适当的方式来处理工作。文档中没有提到任何与 AndroidManifest 声明相关的内容。 https://developer.android.com/topic/libraries/architecture/workmanager/basics - Sasi Kanth
非常抱歉我混淆了 Jobs 和 worker 的概念... 针对您的问题,我认为当应用程序在前台或后台时,Firebase 数据库已经初始化,但是当应用程序被杀掉时,您需要重新初始化数据库...文档中提到如果在其他进程上调用数据库初始化,则会出现奇怪的行为...请检查工作是否在您的主进程上执行? - Anis BEN NSIR
可能是这样。下班后我要试一下,看看 FirebaseApp 是否已经初始化。我没有收到任何异常(如果没有 FirebaseApp 实例存在,通常会抛出异常)。 - Sasi Kanth
任何FirebaseApp的初始化必须仅在应用程序的主进程中进行。在除主进程之外的进程中使用Firebase是不受支持的,可能会导致与资源争用相关的问题。 - Anis BEN NSIR
所以我已经检查了FirebaseApp和FirebaseDatabase的实例,它们都可用。我可以从数据库获取引用路径等等。但是事件监听器没有被调用,仅此而已。 - Sasi Kanth
2个回答

9

您需要阻止执行doWork(),直到所有工作都完成。 目前,由于addListenerForSingleValueEvent是异步的,因此您的函数立即返回SUCCESS,这意味着WorkManager假定一切都已完成并允许您的应用程序进程停止。

一种使函数阻塞的方法是使用CountDownLatch来强制代码等待监听器完成:

override fun doWork(): Result {
    val latch = CountDownLatch(1)
    val firebaseDatabaseRef = FirebaseDatabase.getInstance().reference
    firebaseDatabaseRef.addListenerForSingleValueEvent(object : ValueEventListener {
        override fun onDataChange(dataSnapshot: DataSnapshot) {
            // Handle DataSnapshot
            latch.countDown()
        }

        override fun onCancelled(databaseError: DatabaseError) {
            // Handle DatabaseError
            latch.countDown()
        }
    })

    latch.await()
    return Result.SUCCESS
}

您还需要考虑何时返回不同的结果代码,以告诉WorkManager是否应该重试您的工作完成。


我尝试过这种方法,但不幸的是似乎不起作用。如果我没有为Countdownlatch或Tasks设置超时,它就会无限运行。当应用程序在前台/后台运行时,这很好用,但当应用程序关闭并且需要获取数据时,我遇到了问题。 - Sasi Kanth
我在我的项目中没有遇到任何问题,虽然我没有专门使用CountDownLatch。我使用其他基础设施,但结果是相同的。 - Doug Stevenson
让我建立一个样例项目并尝试一下,这样我就可以找出当前项目中是否有任何配置错误。 - Sasi Kanth
这个在新建的测试项目上是正常运作的。但是在我当前的项目中却无法工作,我一定是配置错了什么地方。我会尝试进行调试,感谢您的帮助。 - Sasi Kanth
@DougStevenson,你介意分享其他基础设施吗? :p 更好的CountDownLatch替代方案? - Santanu Sur

6
据我所见,您正在使用addListenerForSingleValueEvent(),这意味着监听器将精确读取一次数据。这意味着您的onDataChange()方法将触发当前值(如果可用,则从缓存中,否则从Firebase服务器中)并立即停止侦听。在这种情况下,不需要删除侦听器。唯一需要取消addListenerForSingleValueEvent的时间是如果在连接它时没有网络连接,并且客户端没有数据的本地副本,因为有另一个活动侦听器或者它在磁盘上有数据副本。
如果您希望保持监听更改,则应使用addValueEventListener()。使用此类侦听器意味着您的onDataChange()方法会立即调用当前数据,但(与addListenerForSingleValueEvent不同)侦听器在此之后仍然处于活动状态,并且稍后也会调用您的onDataChange()
Android应用程序关闭后,您可以通过不删除它来使用addValueEventListener()。通常,一旦使用了监听器,您还需要根据活动的生命周期将其移除。如果不删除侦听器,则该应用程序仅在短时间内工作,因为当应用程序不在前台时,Android将停止您的服务。这样做是为了节省未使用应用程序时的资源。它还可能阻止您的应用进行任何网络操作,甚至完全终止应用进程。除了将其设置为前台服务,如您已经提到的那样,您无法阻止此情况发生。
对于您的情况,前台服务可能不是最好的选择,也不适合您的用户。请阅读更多关于后台服务限制的信息。
我的建议是使用Firebase Cloud Messaging来在某些内容发生变化时通知您的应用程序。因此,即使用户关闭应用程序,他们也会收到通知。

无论我使用什么事件监听器,它似乎都是有意这样行事的。是的,我已经在使用 FCM,只是在没有网络时尝试一个小的解决方法,以便应用程序可以从缓存中获取。 - Sasi Kanth
好的,那就使用 FCM 吧。那是最好的选择。 - Alex Mamo
是的,我不能接受这个作为答案。因为它并没有回答我所问的问题。我想知道在那种特定情况下事件监听器不起作用的根本原因。 - Sasi Kanth
如果您没有网络连接,是否会从缓存中获取数据? - Alex Mamo
1
我现在明白了。是的,它应该是这样工作的,不幸的是你不能改变这种行为。 - Alex Mamo
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接