Ako v architektúre MVI spracovať udalosti, ktoré nie je potrebné ukladať?
sobes.tech AI
Odpoveď od AI
Na spracovanie jednorazových udalostí (napríklad zobrazenie toastu, navigácia) v MVI, ktoré by nemali prežiť znovu vytvorenie View alebo byť uložené v stave, sa používajú rôzne prístupy:
-
Side Effects (SingleLiveEvent / Channels):
Špeciálny mechanizmus na odosielanie udalostí z ViewModel do View.
SingleLiveEvent(v starších projektoch alebo knižniciach akoandroidx.lifecycle:lifecycle-livedata-ktx), aleboChannelz Flow (v moderných projektoch). Zaručujú, že udalosť bude spracovaná iba raz.// ViewModel s Flow a 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() { // Biznis logika... viewModelScope.launch { _sideEffect.send(SideEffect.ShowToast("Operácia bola úspešne dokončená!")) } } } sealed class SideEffect { data class ShowToast(val message: String) : SideEffect() object NavigateNext : SideEffect() } // V View (Fragment/Activity) sledujeme 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) { // Implementácia zobrazenia toastu } private fun navigateToNextScreen() { // Implementácia navigácie } } -
Jednorazové udalosti v stave:
Menej odporúčaný prístup, ale niekedy použitý v jednoduchých prípadoch. Pridáme do
UiStatepríznak alebo pole, ktoré označuje prítomnosť jednorazovej udalosti. Po spracovaní udalosti vo View, View odošle novýIntentdo ViewModel, aby resetoval tento príznak/pole v stave. To môže skomplikovať logiku a viesť k opätovnému spusteniu udalosti pri nesprávnom spracovaní alebo znovu vytvorení View.// Príklad stavu s jednorazovým príznakom data class MyUiState( val data: List<Item> = emptyList(), val isLoading: Boolean = false, val showSuccessToast: Boolean = false // Príznak pre jednorazovú udalosť ) // V ViewModel pri úspešnej operácii fun processSuccess() { _uiState.update { it.copy(showSuccessToast = true) } } // V View pri spracovaní showSuccessToast = true if (state.showSuccessToast) { showToast("Úspešne!") // Dôležité: odoslať Intent na resetovanie príznaku viewModel.onToastShown() } // V ViewModel na resetovanie príznaku fun onToastShown() { _uiState.update { it.copy(showSuccessToast = false) } }
Najlepší prístup v modernom Android s Flow a MVI je použitie Side Effects cez Channel. Je to čisté, bezpečné a predvídateľné riešenie pre jednorazové udalosti.