【问题标题】:Should I use coroutine in onMessageReceived() of FirebaseMessagingService?我应该在 FirebaseMessagingService 的 onMessageReceived() 中使用协程吗?
【发布时间】:2021-08-23 02:11:50
【问题描述】:

我正在使用 MVVM 设计模式开发一个 Android 应用程序。

我有一个扩展 FirebaseMessagingService 的类 FCMService

如您所知,FCMService 会覆盖 onMessageReceived(remoteMessage: RemoteMessage) 函数。

所以,每当我在onMessageReceived() 函数中收到消息时,我都想通过存储库将其保存到房间数据库中。

它看起来像下面的代码。

class FCMService : FirebaseMessagingService(), KodeinAware {

    override val kodein by closestKodein()
    private val repository: Repository by instance()
    private val scope: CoroutineScope by instance()

    override fun onNewToken(token: String) {
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        CoroutineScope(Dispatchers.IO).lauch{ repository.save(remoteMessage) }
    }
}
class Repository {
   suspend fun save(remoteMessage: RemoteMessage) {
      withContext(Dispatchers.IO) {
         someDAO.save(removeMessage)
      }
   }
}

我阅读了stackoverflow post 并发现onMessageReceived() 函数在后台线程中执行,并且在 onMessageReceived(RemoteMessage message) 中完成的所有工作都应该同步完成。

所以,这里是我的问题,请

  1. 我应该在onMessageRecevied() 函数中使用CoroutineScope(Dispatchers.IO).lauch {} 吗?

  2. 如果不是,那么我可以只使用普通函数,而不是存储库中的挂起函数,我可以从onMessageReceived() 调用它,而无需CoroutineScope(Dispatchers.IO).launch {}。请问从建筑设计的角度来看是否正确?

  3. 这是一个关于协程的问题,但是,正如您所见,我在 IO 线程中通过 FCMService 中的 CoroutineScope(Dispatchers.IO).lauch{ repository.save(remoteMessage) } 启动了一个新协程,但我还通过 Repository 中的 withContext(Dispatchers.IO) { someDAO.save(removeMessage) } 将 coroutineContext 从 IO 切换到了 IO。我觉得withContext(Dispatchers.IO) { someDAO.save(removeMessage) }是不必要的,因为我是从IO切换到IO。请问我说的对吗?

【问题讨论】:

    标签: android firebase-cloud-messaging coroutine


    【解决方案1】:

    我会尽我所能回答。现在回答您的问题。

    Should I use CoroutineScope(Dispatchers.IO).lauch {} in onMessageRecevied() function?
    

    我认为它没有任何问题。 Firebase Messaging Service 基本上仍然是一项服务,所以应该没有问题。我建议您创建一个 Coroutine 范围,如果出现任何问题,您可以取消它。通常在 ViewModel 中我们使用viewModelScope

    所以你可以这样做

    val job = SupervisorJob()
    
     CoroutineScope(job).launch { 
       // Your Stuff here 
    }
    
    override fun onDestroy() {
        job.cancel()
        super.onDestroy()
    }
    

    回答你的第二个问题

    If no, then I can just use normal function, not suspend function in repository and I can call it from onMessageReceived() without CoroutineScope(Dispatchers.IO).launch {}. Is it correct in terms of architectural design point of view please?
    

    我建议您仍然使用您的 Coroutine Scope 而不是直接使用普通函数,因为无论从架构的角度来看,都建议您使用 Room 和 Coroutines,这对您没有任何伤害。

    第三

    It's a question about Coroutine but, as you can see that I launched a new coroutine in IO thread by CoroutineScope(Dispatchers.IO).lauch{ repository.save(remoteMessage) } in FCMService but I also switch the coroutineContext from IO to IO by withContext(Dispatchers.IO) { someDAO.save(removeMessage) } in Repository. I feel that withContext(Dispatchers.IO) { someDAO.save(removeMessage) } is unnecessary because I am switching from IO to IO. Am I right please?
    

    由于您已经在使用Dispatchers.IO,因此您不再需要它是正确的。让它保持withContext(Dispatcher.IO) 只是为了与您的其他结构保持一致。

    【讨论】:

    • 感谢您的回复,那么我只需要在服务中创建 CoroutineScope 并在存储库中删除 withContext(Dispatchers.IO) 即可。对吗?
    • @KisungTae 在服务中创建一个 CouroutineScope 以避免任何错误或泄漏,并且不要摆脱 withContext(Dispatchers.IO)。让它保持原样。取而代之的是通常调用它并在存储库中它会自动转移到IO
    猜你喜欢
    • 2018-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-06
    • 2020-04-17
    相关资源
    最近更新 更多