Sobes.tech
Middle+

Чӣ гуна дар меъмории MVI рӯйдодҳоро, ки зарур нест, нигоҳ дошта нашаванд, бояд баррасӣ кард?

sobes.tech AI

Ҷавоб аз AI

Барои коркарди рӯйдодҳои яккарата (масалан, намоиши toast, навигатсия) дар MVI, ки набояд аз навсозии View ё нигоҳ доштани ҳолат зинда бимонанд, ба роҳҳои гуногун истифода мешаванд:

  1. Side Effects (SingleLiveEvent / Channels):

    Механизми махсус барои фиристодани рӯйдодҳо аз ViewModel ба View. SingleLiveEvent (дар лоиҳаҳои кӯҳна ё китобхонаҳо монанди androidx.lifecycle:lifecycle-livedata-ktx), ё Channel аз Flow (дар лоиҳаҳои муосир). Онҳо кафолат медиҳанд, ки рӯйдод танҳо як маротиба истифода мешавад.

    // ViewModel бо Flow ва 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() {
            // Логикаи бизнес...
            viewModelScope.launch {
                _sideEffect.send(SideEffect.ShowToast("Амалиёт бо муваффақият анҷом ёфт!"))
            }
        }
    }
    
    sealed class SideEffect {
        data class ShowToast(val message: String) : SideEffect()
        object NavigateNext : SideEffect()
    }
    
    // Дар View (Fragment/Activity) ба рӯйдодҳои 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
        }
    
        private fun navigateToNextScreen() {
            // Иҷрои навигатсия
        }
    }
    
  2. Рӯйдодҳои яккарата дар ҳолат:

    Қисман тавсия дода намешавад, аммо дар ҳолатҳои оддӣ истифода мешавад. Мо як рамз ё майдон дар UiState илова мекунем, ки нишон медиҳад, ки рӯйдоди яккарата мавҷуд аст. Пас аз коркард дар View, View ба ViewModel Intent нав мефиристад, то ин рамз/майдонро дар ҳолат нол карда, барқарор кунад. Ин метавонад мураккабсозии логикаро ба вуҷуд орад ва дар ҳолати нодуруст коркард кардан ё навсозии View рӯйдодро такрор кунад.

    // Намунаи ҳолат бо рамзи яккарата
    data class MyUiState(
        val data: List<Item> = emptyList(),
        val isLoading: Boolean = false,
        val showSuccessToast: Boolean = false // Рамз барои рӯйдоди яккарата
    )
    
    // Дар ViewModel дар вақти муваффақият
    fun processSuccess() {
        _uiState.update { it.copy(showSuccessToast = true) }
    }
    
    // Дар View вақте ки showSuccessToast = true
    if (state.showSuccessToast) {
        showToast("Муваффақият!")
        // Муҳим: фиристодани Intent барои нол кардани рамз
        viewModel.onToastShown()
    }
    
    // Дар ViewModel барои нол кардани рамз
    fun onToastShown() {
        _uiState.update { it.copy(showSuccessToast = false) }
    }
    

Беҳтарин роҳ дар Android-и муосир бо Flow ва MVI — истифодаи Side Effects тавассути Channel. Ин тоза, бехатар ва пешгӯишаванда аст барои рӯйдодҳои яккарата.