Sobes.tech
Middle+

Ինչպես մշակել MVI ճարտարապետությունում այն իրադարձությունները, որոնք պահպանում անհրաժեշտ չեն?

sobes.tech AI

Պատասխան AI-ից

Միայն մեկ անգամ տեղի ունեցող իրադարձությունների (օրինակ, տոստի ցուցադրում, նավիգացիա) մշակման համար 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) {
            // Տոստի ցուցադրման իրականացման կոդ
        }
    
        private fun navigateToNextScreen() {
            // Նավիգացիայի իրականացման կոդ
        }
    }
    
  2. Single Use Events in State:

    Ավելի քիչ նախընտրելի տարբերակ, բայց երբեմն օգտագործվում է պարզ դեպքերում: Ավելացնում ենք նշան կամ դաշտ UiState-ում, որը ցույց է տալիս միանգամից օգտագործվող իրադարձության առկայությունը: Իրադարձության մշակման ժամանակ View-ում, View-ը ուղարկում է նոր Intent ViewModel-ին՝ նշան/դաշտը զրոյացնելու համար: Սա կարող է բարդացնել տրամաբանությունը և հնարավոր է կրկնակի գործարկում առաջացնի սխալ կամ View-ի վերականգնման ժամանակ:

    // Օրինակ State՝ միանգամից օգտագործվող նշանով
    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-ով: Սա մաքուր, անվտանգ և կանխատեսելի լուծում է միանգամից օգտագործվող իրադարձությունների համար։