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

标签 android firebase kotlin kotlin-coroutines

使用时 Firebase Cloud Messaging在 Android 上,通常希望通知当前 Activity传入的推送通知。推荐的方法之一是使用 LocalBroadcastManager 发送 Intent来自 FirebaseMessagingService实现到 Activity ( StackOverflow example answer )。

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

LocalBroadcastManager is an application-wide event bus and embraces layer violations in your app: any component may listen events from any other. You can replace usage of LocalBroadcastManager with other implementation of observable pattern, depending on your usecase suitable options may be LiveData or reactive streams.



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

目前,这些本地广播在我们的应用中有两个主要作用:
  • 使用来自推送通知的新数据更新 UI。这样做的方式是每个 Activity关心传入的推送数据有一个广播接收器,它监听适当的消息并更新自己的 View 数据。
  • 如果服务器发送通知以结束 session ,则强制用户注销。这适用于每个具有广播接收器实例的 Activity ,该实例监听注销事件、结束 Activity 并启动登录 Activity 。

  • 在我看来,这些用例在两个建议的替代方案中都有问题:
  • LiveDataActivity 中最容易使用或 Fragment作为 ViewModel 的一部分.然而,ViewModel仅用于那些直接处理 UI 的类。访问 ViewModel来自 FirebaseMessagingService需要一个丑陋的黑客,从架构的角度来看是一个非常糟糕的主意。另外,不同的activity和fragment有不同的ViewModel对象,我不希望服务需要访问它们。
  • 我可以创建一个 Kotlin object (又名单例)与一堆 LiveData属性,有 FirebaseMessagingService更新那些 LiveData来自传入消息的对象,并具有 Activity观察这些更改并将它们复制到自己的 ViewModel 中的 LiveData属性。这样做的问题是双重的:首先,它要求我有两个相同的 LiveData每条数据的对象,ViewModel中的一个和一个在 object ;其次,它不能帮助我处理“注销事件”,因为 LiveData旨在处理不断变化的数据,而不是监听事件流。 (我也许可以使用这个 LiveData Event Wrapper 来处理第二个问题,但对于不打算以这种方式工作的东西,这仍然感觉像是一个糟糕的黑客。)
  • 虽然响应式流,例如 RxJava,可能会满足我的需求,但在过去的几个月里,我已经强制我的团队学习 Kotlin、Android 数据绑定(bind)、Android ViewModel 和一堆其他新东西,我认为它们不会可以采取更多。 RxJava 也是一个重要的东西,仅用于这一用途,我们没有计划重写整个应用程序以利用它来证明它的添加是合理的。

  • 我发现的一个建议是将 Kotlin 协程与 Channel 一起使用s 或 Flow s。这些可以与响应式流非常相似地使用,但(与 RxJava 不同)旨在与 Kotlin 一起使用并受益于 Kotlin 对 Java 的改进。这个选项现在特别有吸引力,因为谷歌已经宣布他们专注于 Android 开发的 Kotlin 而不是 Java。

    虽然这在我看来是最好的选择,但我还没有设法从其他人那里找到任何关于它是否有效以及这种实现是否存在副作用和/或陷阱的反馈。我唯一发现的是一个 open issuekotlinx.coroutines关于需要提供这样的应用程序示例的存储库。虽然我很想贡献这样一个例子,但我认为我对它的了解不足以创建一个好的例子,而且我不希望我的生产应用程序成为试验品。我也不知道将显式协程与 Channel 一起使用是否更好(或合适)或使用 suspendFlow对于这种情况。

    总之:
  • Kotlin 协程及其关联的并发结构是否是处理 Android 之间通信的好方法 ServiceActivity ?
  • 如果是,使用哪种 Kotlin 类型更有意义,ChannelFlow ?
  • 最佳答案

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

    LiveData 可能适用于您要执行的操作。不要将 ViewModel 与 LiveData 混为一谈——它们解决了不同的问题。虽然您认为 ViewModel 只能由处理 UI 的代码访问是正确的,但该指南并未扩展到 LiveData。公开反射(reflect)来自 FirebaseMessagingService 的当前数据的 LiveData 是完全合理的,该数据随后由 ViewModel 获取、转换并传递给 View 。这个 LiveData 可以是一个单例,或者通过你选择的任何依赖注入(inject)基础设施获得。

    请记住,LiveData 实际上只应该用于管理状态变化。它不是您的应用程序可以收听的数据“流”。您将需要确保您的基础设施是基于状态的,以使其正常运行。 FCM 本身不是基于状态的,但是如果您希望 View 响应来自 FCM 的消息,则需要在每条消息之间保留足够的上下文,以确保您的 UI 一致地响应新消息(或完全没有消息) .

    关于android - 使用 Kotlin 协程替换 LocalBroadcastManager 以进行 Firebase 消息传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57917403/

    相关文章:

    android - 此包名称和 SHA-1 的 OAuth2 客户端已存在于另一个项目中

    kotlin - Kotlin 中的普通类和数据类有什么区别?

    android - 在 Sony Xperia NXT 系列(U、Sola、P、S)中安装自定义 Android 内核

    使用数据路径的 Android Intent 过滤器

    firebase - 优化 Firebase 数据库设计

    android - 如何通过 kotlin 代码更改 android 中的笔触颜色?

    android - 如何从协程返回异步操作到 ViewModel

    android - 如何获得用于团队合作的 google map v2 api key

    java - android中使用WebView显示页面时如何处理白屏和清除之前的web缓存?

    firebase - Firestore 规则 - 数据类型验证