在服务和片段之间使用 Flow to "talk"

Using Flow to "talk" between service and fragment

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

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

我的问题:

您的服务不应该与存储库通信,因为它应该属于 UI 模块,因此它必须与进一步与存储库通信的 ViewModel 通信。

你可以在这里阅读我关于 MVVM 模式的回答:

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

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

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

在自述文件部分有一个 link 到 Youtube 的视频,它将深入解释如何使用 MVVM 服务。


同样在您的代码中,您使用了枚举 classes,这没有错,但由于您正在使用,您可以使用 Sealed Classes,它建立在顶部枚举并提供维护严格层次结构的方法。您的枚举 class 以密封 Class 的形式将按以下方式显示:

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

还有关于无法更新数据的问题,建议您尝试

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

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