Hoe om te gaan met gebeurtenissen die niet opgeslagen hoeven te worden in de MVI-architectuur?
sobes.tech AI
Antwoord van AI
Om unieke gebeurtenissen (bijvoorbeeld het tonen van een toast, navigatie) in MVI te verwerken, die niet de View of de staat moeten overleven of in de staat moeten worden opgeslagen, worden verschillende benaderingen gebruikt:
-
Side Effects (SingleLiveEvent / Channels):
Een speciale mechanisme om gebeurtenissen van ViewModel naar View te sturen.
SingleLiveEvent(in oude projecten of bibliotheken zoalsandroidx.lifecycle:lifecycle-livedata-ktx), ofChanneluit Flow (in moderne projecten). Ze garanderen dat het evenement slechts één keer wordt geconsumeerd.// ViewModel met Flow en Channel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch class MyViewModel : ViewModel() { private val _sideEffect = Channel<SideEffect>(Channel.BUFFERED) val sideEffect = _sideEffect.receiveAsFlow() fun doSomething() { // Businesslogica... viewModelScope.launch { _sideEffect.send(SideEffect.ShowToast("Operatie succesvol!")) } } } sealed class SideEffect { data class ShowToast(val message: String) : SideEffect() object NavigateNext : SideEffect() } // In de View (Fragment/Activity) observeren we SideEffect import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch class MyFragment : Fragment() { private val viewModel: MyViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewLifecycleOwner.lifecycleScope.launch { viewModel.sideEffect.collect { effect -> when (effect) { is SideEffect.ShowToast -> showToast(effect.message) SideEffect.NavigateNext -> navigateToNextScreen() } } } } private fun showToast(message: String) { // Implementatie voor toast } private fun navigateToNextScreen() { // Navigatie } } -
Eenmalige gebeurtenissen in de staat:
Minder aanbevolen, maar soms wordt het gebruikt in eenvoudige gevallen. Voeg een vlag of veld toe aan de
UiStatedie aangeeft dat er een eenmalig evenement is. Na verwerking stuurt de View een nieuweIntentnaar de ViewModel om deze vlag of veld in de staat te resetten. Dit kan de logica compliceren en leiden tot herhaalde triggers bij verkeerd beheer of hercreatie van de View.// Voorbeeld van State met een eenmalige vlag data class MyUiState( val data: List<Item> = emptyList(), val isLoading: Boolean = false, val showSuccessToast: Boolean = false // Vlag voor eenmalig evenement ) // In de ViewModel na een succesvolle operatie fun processSuccess() { _uiState.update { it.copy(showSuccessToast = true) } } // In de View bij het verwerken van showSuccessToast = true if (state.showSuccessToast) { showToast("Succes!") // Belangrijk: stuur een Intent om de vlag te resetten viewModel.onToastShown() } // In de ViewModel om de vlag te resetten fun onToastShown() { _uiState.update { it.copy(showSuccessToast = false) } }
De meest aanbevolen aanpak in moderne Android met Flow en MVI is het gebruik van Side Effects via Channel. Dit is een schone, veilige en voorspelbare oplossing voor eenmalige gebeurtenissen.