android - 使用 Flow 在服务和片段之间“对话”
问题描述
2 年多后,我正在用 android/kotlin 的变化“更新”自己,天哪,它改变了很多。
设想
- 我有一个主要活动
MyFragment
和一个MyFragmentViewModel
- 我有前台服务
MyService
- 我有一个存储库,
Flow<MyState>
它应该由 MyFragmentViewModel 和 MySerice 收集 基本上在过去,当我想在未导出的服务和我使用的主要活动之间进行通信时,LocalBroadCastReceiver
它工作得非常好,并消除了两者之间的紧密耦合二。现在它已被弃用,所以我想为什么不在存储库中包含一个在它发生变化时收集的流,这样任何客户端都可以对变化做出反应。
为了简单起见,这里是一些基本的代码相关
enum class MyState{
STATE_LOADING,
STATE_NORMAL,
....
}
class MyRepository(){
//for simplicity there is no private immutable _state for now
val state:MutableStateFlow<MyState> = MutableStateFlow(MyState.STATE_NORMAL)
fun updateState(newState: MyState){
state.value = newState
}
}
class MyFragmentViewModel @Inject constructor(
private val myRepository: MyRepository
): ViewModel(){
fun updateCurrentState(){
myRepository.updateState(MyState.STATE_LOADING)
}
}
@AndroidEntryPoint
class MyService:Service(){
@Inject lateinitvar myRepository: MyRepository
private val myJob = SupervisorJob()
private val myServiceScope = CoroutineScope(Dispachers.IO+myJob)
fun listenForState(){
myServiceScope.launch{
myRepository.state.collect{
when(it)
....
}
}
}
}
发生的情况是,在启动时,collect
MyService 中确实获得了初始值 STATE_NORMAL,但是当我从 MyFragmentViewModel 更新 MyRepository 状态时,服务没有收到该值。
我的问题:
- 我究竟做错了什么?是否与服务范围/协程以及 collect 的工作方式有关?
- 从架构上讲,这是一个好方法还是有更好的方法?
解决方案
您的服务不应该与 Repository 通信,因为它应该在 UI 模块下,因此它必须与进一步与 Repository 通信的 ViewModel 通信。
您可以在此处阅读我对 MVVM 模式的回答:
. 我在这里解释了 MVVM 模式。
此外,对于您的特定用例,我建议您查看此 github-项目:
在自述文件部分有一个指向 Youtube 视频的链接,它将深入解释如何将服务与 MVVM 一起使用。
同样在您的代码中,您使用了枚举类,这并没有错,但是由于您正在使用,您可以使用密封类,它建立在枚举之上并提供维护严格的层次结构。您的枚举类的形式密封类将按以下方式查看:
sealed class MyState{
object State_Loading : MyState()
object State_Normal : MyState()
}
对于你无法更新数据的问题,我建议你试试
fun updateState(newState: MyState){
state.emit( newState)
}
如果这不起作用,您需要使用 Log 在数据通过的每一步进行调试,并知道错误发生在哪里
推荐阅读
- docker - 无法连接到在 docker 中运行的本地 datastax cassandra
- python - 如何在 wagtail 管理员中过滤页面列表,以便编辑者只能看到其中一部分组中的页面?
- ios - 如何将自定义 SCNTechnique 传递添加到特定区域,而不会弄乱 Sceneview 全屏区域的其余部分?
- git - Git - 区分大小写问题
- amazon-web-services - 服务器端加密与客户端加密 - Amazon S3
- python - 将 Pycharm 与 Oracle SQL 数据库连接起来?- 错误:DPI-1047
- ruby-on-rails - 我正在尝试在我的 rails 应用程序(rails 6)中使用 searchkick gem 实现弹性搜索。重新索引模型时出现 SystemStackError
- python - 如何在 Python 中的 IF 语句中从多个返回值中检查变量之一的值
- php - 在 $_GET 变量中存储和签名
- eclipse - Visual Studio Code 中的 Eclipse 插件支持?