使用Kotlin协程替换LocalBroadcastManager进行Firebase消息传递

时间:2019-09-13 04:45:36

标签: android firebase kotlin kotlin-coroutines

在Android上使用Firebase Cloud Messaging时,通常希望将传入的推送通知通知当前Activity。推荐的一种方法是使用LocalBroadcastManagerIntent实现中的FirebaseMessagingService发送到ActivityStackOverflow example answer)。

但是,从1.1.0-alpha01(2018-12-17)版本开始,LocalBroadcastManager is deprecated

  

LocalBroadcastManager是应用程序范围的事件总线,在您的应用程序中包含违反层的行为:任何组件都可以侦听其他任何事件。您可以将LocalBroadcastManager的用法替换为可观察模式的其他实现,具体取决于您的用例,这些选项可能是LiveData或响应流。

尽管此类很可能会保留更长的时间,但我还是想开始清理我们的应用程序,因此我想迁移到更好的东西,然后Google真正删除旧方法。

现在,这些本地广播在我们的应用程序中扮演两个主要角色:

  1. 使用来自推送通知的新数据更新UI。这种工作方式是,每个关心传入推送数据的Activity都有一个广播接收器,该接收器侦听适当的消息并更新自己的视图数据。
  2. 如果服务器发送结束会话的通知,则强制用户注销。这适用于每个活动都有广播接收器实例的实例,该实例侦听注销事件,结束该活动,然后启动“登录”活动。

如我所见,这些用例在两个建议的替代方案上都有问题:

  • LiveData最容易在Activity中作为FragmentViewModel使用。但是,ViewModel仅用于直接处理UI的那些类。从ViewModel内部访问FirebaseMessagingService的做法很丑陋,从架构的角度来看,这是一个非常糟糕的主意。另外,不同的活动和片段具有不同的ViewModel对象,并且我不希望该服务需要全部访问它们。
  • 我可以创建带有一堆object属性的Kotlin LiveData(也称为Singleton),让FirebaseMessagingService从传入消息中更新那些LiveData对象,并让Activity观察这些更改并将其复制到其自己的ViewModel的{​​{1}}属性中。问题是双重的:首先,它要求我为每个数据段使用两个相同的LiveData对象,一个在LiveData中,一个在ViewModel中。其次,它对处理“注销事件”没有帮助,因为object是用来处理变化的数据,而不是监听事件流的。 (我也许可以使用此LiveData Event Wrapper处理第二个问题,但是对于某些不适合这种方式的事情,这仍然感觉很糟糕。)
  • 尽管反应式流(例如RxJava)可能会满足我的需要,但我已经强迫我的团队在过去的几个月中学习Kotlin,Android Databinding,Android ViewModel和其他一系列新内容,但我没有认为他们可以拿更多。 RxJava只是为此用途而添加的一件大事,并且我们没有计划重写整个应用程序以利用它来证明其添加合理性的计划。

我发现一个建议是将Kotlin Coroutines与LiveDataChannel s一起使用。它们可以与响应流非常相似地使用,但是(与RxJava不同)旨在与Kotlin一起使用,并受益于Kotlin对Java的改进。由于Google宣布他们将重点放在Kotlin而不是Java上,因此该选项特别具有吸引力。

虽然在我看来这是最好的选择,但我还没有从其他人那里获得任何反馈,有关该反馈是否有效以及这种实现是否有副作用和/或陷阱。我发现的唯一一件事是Flow存储库中的open issue,有关需要提供这样一个应用程序示例的需求。尽管我很乐意提供这样的示例,但我认为我对它的了解还不够,无法创建一个很好的示例,并且我不希望我的生产应用成为豚鼠。我也不知道在这种情况下将显式的协程与kotlinx.coroutines一起使用还是将Channelsuspend一起使用是否更好(或更合适)。

总结:

  • Kotlin协程及其相关的并发结构是否是处理Android FlowService之间通信的好方法?
  • 如果是,ActivityChannel是哪种更适合使用Kotlin类型?

1 个答案:

答案 0 :(得分:2)

协程对于将数据从一个软件组件传递到另一软件组件并没有真正帮助。它们使用看起来好像是同步的语法来帮助处理异步工作的多个单元。那是协程的底线。它们类似于JavaScript中的async / await语法。虽然您可能使用协程从异步源访问数据,但它并没有给您任何原始手段将数据代理到其他组件上。

LiveData可能可以很好地满足您的需求。不要将ViewModel与LiveData混淆-它们可以解决不同的问题。尽管您正确地认为ViewModel仅应由处理UI的代码访问,但该准则不会扩展到LiveData。公开一个反映FirebaseMessagingService中当前数据的LiveData,这是合理的,以后再由ViewModel拾取,转换并传递给视图。此LiveData可以是单例,也可以通过您选择的任何依赖项注入基础结构来获取。

请记住,LiveData实际上仅应用于管理状态更改。这不是您的应用程序可以收听的数据“流”。您需要确保您的基础架构是基于状态的,以使其正常运行。 FCM本身不是基于状态的,但是如果您希望您的视图响应来自FCM的消息,则需要在每条消息之间保留足够的上下文,以确保您的UI对新消息(或完全没有消息)做出一致的响应。