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.
CodePudding user response:
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()
}
}
}
CodePudding user response:
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