Need to collect flow in ViewModel and after some data modification, the UI is updated using _batteryProfileState
.
Inside compose I am collecting states like this
val batteryProfile by viewModel.batteryProfileState.collectAsStateWithLifecycle()
batteryProfile.voltage
In ViewModel
private val _batteryProfileState = MutableStateFlow(BatteryProfileState())
val batteryProfileState = _batteryProfileState.asStateFlow()
private fun getBatteryProfileData() {
viewModelScope.launch {
// FIXME In viewModel we should not collect it like this
_batteryProfile(Unit).collect { result ->
_batteryProfileState.update { state ->
when(result) {
is Result.Success -> {
state.copy(
voltage = result.data.voltage?.toString()
?.plus(result.data.voltageUnit
)
}
is Result.Error -> {
state.copy(
errorMessage = _context.getString(R.string.something_went_wrong)
)
}
}
}
}
}
}
The problem is when I put my app in the background the _batteryProfile(Unit).collect
does not stop collecting while in UI batteryProfile.voltage
stop updating UI which is correct behavior as I have used collectAsStateWithLifecycle()
for UI.
But I have no idea how to achieve the same behavior for ViewModel.
Note I need to collect this data in method getBatteryProfileData()
because this function needs to call from two places i.e initially inside init of ViewModel and from refresh
CodePudding user response:
try adding a variable to your ViewModel that tracks the activity state, and update it onResume() and onPause(). Then in your getBatteryProfileData() function, check that variable (stop and restart the Flow depending on what you see).
So in your activity:
val inForeground = false
onResume(){
....
inForeground = true
}
onPause(){
....
inForeground = false
}
CodePudding user response:
You can try to define getBatteryProfileData() as suspend fun:
suspend fun getBatteryProfileData() {
// FIXME In viewModel we should not collect it like this
_batteryProfile(Unit).collect { result ->
_batteryProfileState.update { state ->
when(result) {
is Result.Success -> {
state.copy(
voltage = result.data.voltage?.toString()
?.plus(result.data.voltageUnit
)
}
is Result.Error -> {
state.copy(
errorMessage = _context.getString(R.string.something_went_wrong)
)
}
}
}
}
}
And than in your composable define scope:
scope = rememberCoroutineScope()
scope.launch {
yourviewmodel.getBatteryProfileData()
}
And I think you can move suspend fun getBatteryProfileData() out of ViewModel class...
CodePudding user response:
You should use collectAsStateWithLifecycle()
, check this blog post.