在Android上使用Firebase Cloud Messaging时,通常希望将传入的推送通知通知当前Activity
。推荐的一种方法是使用 LocalBroadcastManager
将Intent
从FirebaseMessagingService
实现发送到Activity
(StackOverflow example answer)。
但是,从版本1.1.0-alpha01(2018-12-17)开始, LocalBroadcastManager
is deprecated:
尽管此类很可能会保留更长的时间,但我还是想开始清理我们的应用程序,因此我想迁移到更好的方法,然后Google真正删除旧方法。
目前,这些本地广播在我们的应用程序中具有两个主要角色:
Activity
都有一个广播接收器,该接收器监听适当的消息并更新其自己的 View 数据。 如我所见,这些用例在两个建议的替代方案上都有问题:
LiveData
最容易在Activity
或Fragment
中用作ViewModel
的一部分。但是,ViewModel
仅应在直接处理UI的那些类中使用。从ViewModel
中访问FirebaseMessagingService
很难受,这从体系结构的角度来看是一个非常糟糕的主意。另外,不同的 Activity 和 fragment 具有不同的ViewModel
对象,我不希望该服务需要访问它们全部。 object
属性创建Kotlin LiveData
(又称Singleton),让FirebaseMessagingService
从传入消息中更新这些LiveData
对象,让Activity
观察这些更改并将其复制到自己的ViewModel
的LiveData
属性中。问题是双重的:首先,它要求我为每个数据段使用两个相同的LiveData
对象,一个在ViewModel
中,一个在object
中;其次,它对我处理“注销事件”没有帮助,因为LiveData
旨在处理更改的数据,而不是监听事件流。 (我可以使用 LiveData
Event Wrapper来处理第二个问题,但是对于某些不适合这种方式的事情,这仍然感觉很糟糕。)我发现的一个建议是将Kotlin Coroutines与
Channel
或Flow
一起使用。它们可以与响应流非常相似地使用,但是(与RxJava不同)旨在与Kotlin一起使用,并且可以从Kotlin对Java的改进中受益。由于Google已经宣布他们专注于Android开发而不是Java的Kotlin,因此此选项特别具有吸引力。虽然在我看来这是最好的选择,但我还没有从其他人那里获得任何反馈,有关它是否有效以及这种实现是否有副作用和/或陷阱。我发现的唯一一件事是
kotlinx.coroutines
存储库上的open issue,它需要提供这样的应用程序示例。虽然我想贡献这样一个例子,但我认为我对它的了解还不足以创建一个很好的例子,并且我不希望我的生产应用程序成为豚鼠。我也不知道在这种情况下将显式Couroutines与Channel
一起使用还是将suspend
与Flow
一起使用是否更好(或更合适)。总之:
Service
和Activity
之间通信的好方法吗? Channel
或Flow
? 最佳答案
协程并不能真正帮助将数据从一个软件组件传递到另一个软件组件。它们使用看起来好像是同步的语法来帮助处理异步工作的多个单元。那是协程的底线。它们类似于JavaScript中的async/await语法。尽管您可能使用协程从异步源访问数据,但是它并没有给您提供将这些数据代理到其他组件的任何先决条件。
LiveData可能可以很好地满足您的需求。不要将ViewModel与LiveData混淆-它们可以解决不同的问题。尽管您正确地认为ViewModel仅应由处理UI的代码访问,但该指导方针并没有扩展到LiveData。公开一个反射(reflect)FirebaseMessagingService中当前数据的LiveData,这是合理的,以后再由ViewModel拾取,转换并传递给 View 。此LiveData可以是单例,也可以通过您选择的任何依赖项注入(inject)基础结构获得。
请记住,LiveData实际上仅应用于管理状态更改。它不是您的应用程序可以收听的数据“流”。您将需要确保您的基础架构是基于状态的,以使其正常运行。 FCM本身不是基于状态的,但是如果您希望 View 响应来自FCM的消息,则需要在每条消息之间保留足够的上下文,以确保您的UI对新消息(或完全没有消息)做出一致的响应。 。