Kaip MVI architektūroje tvarkyti įvykius, kurių nereikia išsaugoti?
sobes.tech AI
Atsakymas iš AI
Vienkartinių įvykių (pavyzdžiui, tostų rodymas, navigacija), kurie neturėtų išlikti per View perkūrimą ar būti išsaugoti būsenoje, apdorojimui MVI naudojami įvairūs požiūriai:
-
Side Effects (SingleLiveEvent / Channels):
Specialus mechanizmas, skirtas siųsti įvykius iš ViewModel į View:
SingleLiveEvent(senesniuose projektuose arbaandroidx.lifecycle:lifecycle-livedata-ktxbibliotekose), arbaChanneliš Flow. Jie garantuoja, kad įvykis bus suvartotas tik vieną kartą:// ViewModel su Flow ir 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() { // Verslo logika... viewModelScope.launch { _sideEffect.send(SideEffect.ShowToast("Veiksmas sėkmingai atliktas!")) } } } sealed class SideEffect { data class ShowToast(val message: String) : SideEffect() object NavigateNext : SideEffect() } // Vaizdas (Fragment/Activity) stebi 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) { // Tosto rodymo įgyvendinimas } private fun navigateToNextScreen() { // Navigacijos įgyvendinimas } } -
Vienkartiniai įvykiai būsenoje:
Mažiau pageidaujamas požiūris, bet kartais naudojamas paprastiems atvejams. Pridedame žymeklį arba lauką
UiState, kuris nurodo vienkartinį įvykį. Po įvykio apdorojimo View, ViewModel gauna naująIntent, kad išvalytų šį žymeklį/lauką. Tai gali apsunkinti logiką ir sukelti pakartotinį įvykdymą dėl netinkamo apdorojimo arba perkūrimo:// Pavyzdys su būsena ir vienkartiniu žymekliu data class MyUiState( val data: List<Item> = emptyList(), val isLoading: Boolean = false, val showSuccessToast: Boolean = false // Žymeklis vienkartiniam įvykiui ) // ViewModel'e po sėkmingo veiksmo fun processSuccess() { _uiState.update { it.copy(showSuccessToast = true) } } // View'e, kai showSuccessToast = true if (state.showSuccessToast) { showToast("Sėkmingai!") // Svarbu: išvalyti žymeklį, siunčiant Intent viewModel.onToastShown() } // ViewModel'e žymeklio išvalymas fun onToastShown() { _uiState.update { it.copy(showSuccessToast = false) } }
Modernus Android su Flow ir MVI geriausias būdas — naudoti Side Effects per Channel. Tai švarus, saugus ir prognozuojamas sprendimas vienkartiniams įvykiams.