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

2024-05-11

使用时Firebase 云消息传递 https://firebase.google.com/docs/cloud-messaging/android/client在 Android 上,通常需要通知当前Activity传入的推送通知。推荐的方法之一是使用LocalBroadcastManager https://developer.android.com/reference/androidx/localbroadcastmanager/content/LocalBroadcastManager.html发送一个Intent来自FirebaseMessagingService实施到Activity (StackOverflow 示例答案 https://stackoverflow.com/a/41931325/829970).

然而,从版本1.1.0-alpha01(2018-12-17)开始,LocalBroadcastManager已弃用 https://developer.android.com/reference/androidx/localbroadcastmanager/content/LocalBroadcastManager.html:

LocalBroadcastManager 是一个应用程序范围的事件总线,并包含应用程序中的层违规:任何组件都可以侦听来自任何其他组件的事件。您可以替换使用LocalBroadcastManager对于可观察模式的其他实现,根据您的用例,合适的选项可能是LiveData https://developer.android.com/reference/androidx/lifecycle/LiveData.html或反应流。

虽然这个类很可能会保留一段时间,但我还是想开始清理我们的应用程序,所以我想在 Google 真正删除旧方法之前迁移到更好的东西。

目前,这些本地广播在我们的应用程序中有两个主要角色:

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

在我看来,这些用例的建议替代方案都存在问题:

  • LiveData最容易使用在Activity or Fragment作为一个ViewModel。然而,ViewModel仅适用于那些直接处理 UI 的类。访问ViewModel从内部FirebaseMessagingService这是一个丑陋的黑客行为,从架构的角度来看是一个非常糟糕的主意。此外,不同的活动和片段有不同的ViewModel对象,并且我不希望服务需要访问所有对象。
  • 我可以创建一个 Kotlinobject(又名 Singleton)与一堆LiveData属性,具有FirebaseMessagingService更新那些LiveData来自传入消息的对象,并且具有Activity观察这些变化并将它们复制到自己的变化中ViewModel's LiveData特性。这样做的问题是双重的:首先,它要求我有两个相同的LiveData每条数据的对象,一个在ViewModel和一个在object;其次,它不能帮助我处理“注销事件”,因为LiveData旨在处理不断变化的数据,而不是监听事件流。 (我也许可以使用这个来处理第二个问题LiveData事件包装器 https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150,但这仍然感觉像是对不应该以这种方式工作的东西的糟糕黑客攻击。)
  • 虽然响应式流(例如 RxJava)可能会满足我的需要,但在过去的几个月里,我已经迫使我的团队学习 Kotlin、Android 数据绑定、Android ViewModel 以及许多其他新东西,而且我认为它们不会可以采取更多。 RxJava 对于这一用途来说也是一个需要添加的大东西,我们不打算重写整个应用程序来利用它来证明其添加的合理性。

我发现的一项建议是将 Kotlin Coroutines 与Channels or Flows。它们的使用方式与反应式流非常相似,但(与 RxJava 不同)旨在与 Kotlin 一起使用,并受益于 Kotlin 对 Java 的改进。既然 Google 已经宣布他们将重点使用 Kotlin 而不是 Java 来进行 Android 开发,那么这个选项就特别有吸引力。

虽然这在我看来是最好的选择,但我还没有找到其他人关于它是否有效以及这种实现是否存在副作用和/或陷阱的任何反馈。我唯一发现的是开放问题 https://github.com/Kotlin/kotlinx.coroutines/issues/945 on the kotlinx.coroutines关于需要提供此类应用程序示例的存储库。虽然我很乐意提供这样的示例,但我认为我对它的了解还不足以创建一个好的示例,而且我不希望我的生产应用程序成为小白鼠。我也不知道使用显式协程是否更好(或正确)Channel或使用suspend with Flow对于这个案例。

总之:

  • Kotlin 协程及其关联的并发结构是处理 Android 之间通信的好方法吗Service and Activity?
  • 如果是,哪种 Kotlin 类型更适合使用,Channel or Flow?

协程并不能真正帮助将数据从一个软件组件移交到另一个软件组件。它们使用看似同步的语法帮助处理多个异步工作单元。这是协程的底线。它们类似于 JavaScript 中的 async/await 语法。虽然您可能使用协程从异步源访问数据,但它不会为您提供任何将数据代理到其他组件的原语。

LiveData 可能可以很好地满足您想要做的事情。不要将 ViewModel 与 LiveData 混为一谈——它们解决不同的问题。虽然您认为 ViewModel 只能由处理 UI 的代码访问是正确的,但该指南不会扩展到 LiveData。公开一个反映来自 FirebaseMessagingService 的当前数据的 LiveData 是完全合理的,该数据随后由 ViewModel 拾取、转换并传递到视图。此 LiveData 可以是单例,也可以通过您选择的任何依赖项注入基础设施获得。

请记住,LiveData 实际上只应该用于管理状态更改。它不是您的应用程序可以监听的数据“流”。您需要确保您的基础设施是基于状态的,才能顺利进行。 FCM 本身不是基于状态的,但如果您希望视图响应来自 FCM 的消息,则需要在每条消息之间保留足够的上下文,以确保您的 UI 一致地响应新消息(或完全缺少消息) 。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Kotlin 协程替换 LocalBroadcastManager 以进行 Firebase 消息传递 的相关文章

随机推荐