I've an Activity A, with it's ViewModel with StateFlow UI State implementation as said in Android's documentation.
class A_ViewModel: ViewModel() {
private val _uiState = MutableStateFlow(UIState.None)
val uiState: StateFlow<UIState> = _uiState
fun onButtonClicked() {
_uiState.value = UIState.NavigateToB
}
}
class A_Activity: AppCompatActivity() {
private val viewModel = // getViewModel()
override fun onCreate() {
button.setOnClickListener {
viewModel.onButtonClicked()
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { uiState ->
when (uiState) {
is UIState.NavigateToB -> {
startActivity(Intent(this, B::class.java))
}
.
.
else -> { /* do nothing */ }
}
}
}
}
}
}
The problem I'm facing is, when I return back from Activity B to Activity A, since viewModel.uiState.collect { } is called again in onStart() of Activity A, the latest value (UIState.NavigateToB) gets replayed again and Activity B is again launched.
This seems to be a very trivial issue. But I'm unable to think of a safe solution for this.
Sure, there are successful work arounds like setting uiState.value = UIState.None in the onStop() of Activity A. But I'm unable to think of an elegant way of handling this.
For one time events you can use Channels instead of flows like this:
private val _uiState:Channel<UIState> = Channel()
val uiState = _uiState.receiveAsFlow()
also, you can use MutableSharedFlow if you want more flexibility like to have multiple consumers or keep the last value without recollecting that like this:
private val _uiState:MutableSharedFlow<UIState> = MutableSharedFlow(extraBufferCapacity=1)
val uiState:Flow<UIState> = _uiState
for navigation I have a detached field SharedFlow and uiState is used only for UI state, for instance:
in viewmodel
private val _goTo = MutableSharedFlow<NotPrefsRoute>(replay = 0, extraBufferCapacity = 1)
val goTo: SharedFlow<NotPrefsRoute> = _goTo
...
sealed class NotPrefsRoute {
object Back : NotPrefsRoute()
object NotificationSettings : NotPrefsRoute()
}
in fragment
launchAndRepeatWithViewLifecycle {
viewModel.goTo.collect {
when (it) {
Back -> findNavController().popBackStack()
NotificationSettings -> activity?.openNotificationSettings()
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With