After more than 2 years, I am "updating" myself with android/kotlin changes, and boy, has it changed a lot.
Scenario
- I have a main activity with
MyFragment
and aMyFragmentViewModel
- I have a foreground service
MyService
- I have a repository that has a
Flow<MyState>
which should be collected by both MyFragmentViewModel and MySerice Basically in the past, when I wanted to communicate between a not exported service and the main activity I've usedLocalBroadCastReceiver
which worked really well and removed the tight coupling between the two. Now that is deprecated so I thought why not have in the Repository a Flow that gets collected whenever it changes, so any client can react to changes.
Here is, for the sake of simplicity, some basic code related
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)
....
}
}
}
}
What happens is that on starting, the collect
in MyService does get the initial value STATE_NORMAL but when from MyFragmentViewModel I update the MyRepository state, this value is not received by the service.
My questions:
- what am I doing wrong? Is something related to service scope/coroutines and how collect works?
- is this a good approach, architecturally speaking or are there better way to do it?