2年多了,我在"更新"。我自己与android/kotlin的变化,天哪,它改变了很多。
场景
- 我有
MyFragment
和MyFragmentViewModel
的主要活动 - 我有一个前台服务
MyService
- 我有一个存储库,它有一个
Flow<MyState>
,应该由MyFragmentViewModel和myservice收集基本上在过去,当我想要在未导出的服务和主要活动之间进行通信时,我使用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)
....
}
}
}
}
发生的事情是,在启动时,MyService中的collect
确实获得初始值STATE_NORMAL,但当我从MyFragmentViewModel更新MyRepository状态时,该值未被服务接收。
我的问题:
- 我做错了什么?是否与服务范围/协同程序以及collect的工作方式有关? 从架构上讲,这是一个好方法吗?还是有更好的方法?
你的服务永远不应该与存储库通信,因为它应该在UI模块下,因此它必须与ViewModel通信,后者进一步与存储库通信。
你可以在这里阅读我对MVVM模式的回答:
这是正确的Android MVVM设计吗?
。我已经在这里解释了MVVM模式。
对于您的特定用例,我建议您检查这个github - project:
https://github.com/mitchtabian/Bound-Services-with-MVVM在ReadMe部分有一个Youtube视频的链接,该视频将深入解释如何使用MVVM服务。
同样在你的代码中,你已经使用了枚举类,这是没有错的,但是因为你正在使用,你可以使用密封类,它是建立在enum之上的,并提供了维护严格的层次结构。你的密封类形式的枚举类将以以下方式呈现:
sealed class MyState{
object State_Loading : MyState()
object State_Normal : MyState()
}
对于您无法更新数据的问题,我建议您尝试
fun updateState(newState: MyState){
state.emit( newState)
}
如果这不起作用,您需要使用Log从数据经过的每一步进行调试,并知道错误发生在哪里