首页 > 解决方案 > 使用 Flow 在服务和片段之间“对话”

问题描述

2 年多后,我正在用 android/kotlin 的变化“更新”自己,天哪,它改变了很多。

设想

为了简单起见,这里是一些基本的代码相关

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)
               ....
         }
     }
  }
}

发生的情况是,在启动时,collectMyService 中确实获得了初始值 STATE_NORMAL,但是当我从 MyFragmentViewModel 更新 MyRepository 状态时,服务没有收到该值。

我的问题:

标签: androidkotlin-flow

解决方案


您的服务不应该与 Repository 通信,因为它应该在 UI 模块下,因此它必须与进一步与 Repository 通信的 ViewModel 通信。

您可以在此处阅读我对 MVVM 模式的回答:

这是正确的 Android MVVM 设计吗?

. 我在这里解释了 MVVM 模式。

此外,对于您的特定用例,我建议您查看此 github-项目:

https://github.com/mitchtabian/Bound-Services-with-MVVM

在自述文件部分有一个指向 Youtube 视频的链接,它将深入解释如何将服务与 MVVM 一起使用。


同样在您的代码中,您使用了枚举类,这并没有错,但是由于您正在使用,您可以使用密封类,它建立在枚举之上并提供维护严格的层次结构。您的枚举类的形式密封类将按以下方式查看:

sealed class MyState{
   object State_Loading : MyState()
   object State_Normal : MyState()
}

对于你无法更新数据的问题,我建议你试试

fun updateState(newState: MyState){
       state.emit( newState)
   }

如果这不起作用,您需要使用 Log 在数据通过的每一步进行调试,并知道错误发生在哪里


推荐阅读