Wie behandelt man in der MVI-Architektur Ereignisse, die nicht gespeichert werden müssen?
sobes.tech KI
Antwort von AI
Um Events-Handling-Ansatz in MVI, der Einmalereignisse (z.B. Toast anzeigen, Navigation) behandelt, die nicht die View-Neuerstellung überleben oder im Zustand gespeichert werden sollen, umfasst verschiedene Methoden:
-
Side Effects (SingleLiveEvent / Channels):
Ein spezieller Mechanismus, um Ereignisse vom ViewModel zur View zu senden.
SingleLiveEvent(in älteren Projekten oder Bibliotheken wieandroidx.lifecycle:lifecycle-livedata-ktx) oderChannelaus Flow (in modernen Projekten). Sie garantieren, dass das Ereignis nur einmal konsumiert wird.// ViewModel mit Flow und 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() { // Business-Logik... viewModelScope.launch { _sideEffect.send(SideEffect.ShowToast("Operation erfolgreich!")) } } } sealed class SideEffect { data class ShowToast(val message: String) : SideEffect() object NavigateNext : SideEffect() } // In der View (Fragment/Activity) beobachten wir 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) { // Toast anzeigen } private fun navigateToNextScreen() { // Navigation } } -
Single-Use-Events im State:
Weniger bevorzugt, aber manchmal in einfachen Fällen verwendet. Es wird ein Flag oder Feld im
UiStatehinzugefügt, das auf das Vorhandensein eines Einmal-Events hinweist. Nach der Verarbeitung sendet die View einen neuenIntentan das ViewModel, um dieses Flag im Zustand zurückzusetzen. Dies kann die Logik verkomplizieren und bei falscher Handhabung oder View-Rekonstruktion zu wiederholtem Auslösen führen.// Beispiel für State mit Einmal-Flag data class MyUiState( val data: List<Item> = emptyList(), val isLoading: Boolean = false, val showSuccessToast: Boolean = false // Flag für Einmal-Event ) // Im ViewModel nach erfolgreicher Operation fun processSuccess() { _uiState.update { it.copy(showSuccessToast = true) } } // In der View bei Verarbeitung von showSuccessToast = true if (state.showSuccessToast) { showToast("Erfolg!") // Wichtig: Intent zum Zurücksetzen des Flags senden viewModel.onToastShown() } // Im ViewModel zum Zurücksetzen des Flags fun onToastShown() { _uiState.update { it.copy(showSuccessToast = false) } }
Der am besten empfohlene Ansatz in modernem Android mit Flow und MVI ist die Verwendung von Side Effects über Channel. Dies ist eine saubere, sichere und vorhersehbare Lösung für Einmal-Events.