MVVM 到 MVI:Android 架構(gòu)遷移指南

關(guān)注個人簡介,技術(shù)不迷路~

從模型-視圖-視圖模型 (MVVM) 架構(gòu)遷移到模型-視圖-意圖 (MVI) 架構(gòu)似乎是一項艱巨的任務(wù)。但憑借更清晰的架構(gòu)和更可預(yù)測的應(yīng)用程序行為的好處,這是一次非常值得付出努力的轉(zhuǎn)變。

在本文中,我們將探討 MVVM 和 MVI 之間的差異,并提供有關(guān)如何遷移到 MVI 的指導(dǎo)。

MVVM 與 MVI

MVVM 架構(gòu)是移動應(yīng)用程序開發(fā)中廣泛使用的模式。它將用戶界面(View)與數(shù)據(jù)和邏輯(ViewModel)分開,并允許兩個組件之間進(jìn)行數(shù)據(jù)綁定。ViewModel 負(fù)責(zé)為 View 準(zhǔn)備數(shù)據(jù)并處理用戶輸入。

另一方面,MVI 架構(gòu)是近年來流行的一種較新的模式。它還將視圖和數(shù)據(jù)分開,但添加了一個稱為意圖的新層,該層負(fù)責(zé)以結(jié)構(gòu)化且可預(yù)測的方式表示用戶操作。Intent 被傳遞給模型,模型產(chǎn)生一個新的狀態(tài),然后顯示在視圖中。

兩種架構(gòu)之間的主要區(qū)別在于,在 MVVM 中,ViewModel 負(fù)責(zé)用戶操作和更新視圖狀態(tài)。在 MVI 中,意圖是一個代表用戶操作的獨(dú)立層,可以更輕松地推斷應(yīng)用程序行為并處理邊緣情況。

為什么選擇 MVI?

1.更好的關(guān)注點分離: 使用MVI,Intent層負(fù)責(zé)用戶操作,Model層負(fù)責(zé)狀態(tài)管理,View層負(fù)責(zé)狀態(tài)渲染。這種分離使得推斷應(yīng)用程序行為以及對應(yīng)用程序進(jìn)行更改變得更加容易,而不會影響架構(gòu)的其他部分。

2. 更可預(yù)測的應(yīng)用程序行為: 使用 MVI,應(yīng)用程序的狀態(tài)始終由單個數(shù)據(jù)對象表示,這使得更容易推理和預(yù)測應(yīng)用程序的行為。這種可預(yù)測性可以減少錯誤并提供更好的用戶體驗。

3. 提高可測試性: MVI 使編寫單元測試變得更加容易,因為每一層都可以獨(dú)立測試。通過架構(gòu)的可預(yù)測數(shù)據(jù)流使得編寫涵蓋所有可能狀態(tài)和邊緣情況的測試變得更加容易。

如何從 MVVM 遷移到 MVI?

從 MVVM 遷移到 MVI 似乎是一項艱巨的任務(wù),但重要的是要記住這是一個漸進(jìn)的過程。以下是一些需要考慮的步驟:

  1. 了解MVI架構(gòu): 在進(jìn)行切換之前,請確保您了解MVI的關(guān)鍵概念,包括Intent層和單向數(shù)據(jù)流。
  2. 識別組件: 仔細(xì)查看現(xiàn)有的 MVVM 代碼并識別需要更改的組件。這包括 ViewModel、View 以及任何數(shù)據(jù)模型或存儲庫。
  3. 創(chuàng)建 Intent 層:將 Intent 層添加到您的應(yīng)用程序中,該層以結(jié)構(gòu)化且可預(yù)測的方式表示用戶操作。該層應(yīng)該與 ViewModel 和 Model 分開。
  4. 更新 ViewModel: 修改您的 ViewModel 以接受 Intent 并將其傳遞給模型。ViewModel 不應(yīng)再負(fù)責(zé)更新 View 的狀態(tài)
  5. 更新模型: 修改模型以根據(jù)意圖和當(dāng)前狀態(tài)生成新狀態(tài)。模型不應(yīng)再負(fù)責(zé)處理用戶輸入。
  6. 更新視圖: 修改視圖以呈現(xiàn)模型提供的狀態(tài)。視圖不應(yīng)再負(fù)責(zé)獲取數(shù)據(jù)或更新狀態(tài)。
  7. *****為架構(gòu)的每一層* **編寫單元測試,以確保數(shù)據(jù)流可預(yù)測,并覆蓋所有可能的狀態(tài)和邊緣情況。****

從 MVVM 遷移到 MVI 的實施主要步驟

第 1 步:創(chuàng)建 Intent 類


sealed class MyIntent {  
object LoadData : MyIntent()  
data class UpdateData(val newData: Data) : MyIntent()  
object DeleteData : MyIntent()  
}

第2步:修改ViewModel

修改您的 ViewModel 以接受意圖并將其傳遞給模型。ViewModel 不應(yīng)再負(fù)責(zé)更新 View 的狀態(tài)。

class  MyViewModel ( private  val myModel: MyModel) : ViewModel() { 
    private  val _state = MutableLiveData<MyState>() 
    val state: LiveData<MyState> = _state 

    fun  processIntent (intent: MyIntent ) { 
        val newState = myModel.processIntent(intent, _state.value) 
        _state.postValue(newState) 
    } 
}

第三步:創(chuàng)建State類

創(chuàng)建一個表示應(yīng)用程序當(dāng)前狀態(tài)的類,例如:

class MyModel(private val myRepository: MyRepository) {
    fun processIntent(intent: MyIntent, currentState: MyState?): MyState {
        return when (intent) {
            is MyIntent.LoadData -> {
                // Load data from repository
                myRepository.getData()
                    .map { data -> currentState?.copy(data = data) ?: MyState(data = data) }
                    .onStart { emit(currentState?.copy(isLoading = true) ?: MyState(isLoading = true)) }
                    .onErrorReturn { throwable ->
                        currentState?.copy(isLoading = false, error = throwable)
                            ?: MyState(isLoading = false, error = throwable)
                    }
            }
            is MyIntent.UpdateData -> {
                // Update data in repository
                myRepository.updateData(intent.newData)
                currentState?.copy(data = intent.newData) ?: MyState(data = intent.newData)
            }
            is MyIntent.DeleteData -> {
                // Delete data from repository
                myRepository.deleteData()
                MyState()
            }
        }
    }
}

第5步:修改視圖

修改視圖以呈現(xiàn)模型提供的狀態(tài)。視圖不應(yīng)再負(fù)責(zé)獲取數(shù)據(jù)或更新狀態(tài)。

class MyActivity : AppCompatActivity() {
    private val viewModel: MyViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_my)

        viewModel.state.observe(this, Observer { state ->
            // Render state in UI
            when {
                state.isLoading -> showLoading()
                state.error != null -> showError(state.error)
                state.data != null -> showData(state.data)
            }
        })
    }

    private fun showLoading() {
        // Show loading spinner or progress bar
    }

    private fun showError(error: Throwable) {
        // Show error message
    }

    private fun showData(data: Data) {
        // Show data in UI
    }
}

結(jié)論

總之,從 MVVM 遷移到 MVI 可以為您的 Android 應(yīng)用帶來多項好處。通過采用 MVI 架構(gòu),您可以創(chuàng)建更具反應(yīng)性、可預(yù)測性和可測試性的應(yīng)用程序,同時減少層之間的耦合并提高代碼庫的整體可維護(hù)性。

MVI 允許您將用戶交互建模為意圖,根據(jù)這些意圖更新應(yīng)用程序的狀態(tài),然后在 UI 中呈現(xiàn)該狀態(tài)。這使得您可以更輕松地推斷應(yīng)用程序中的數(shù)據(jù)流,并更改代碼,而不會引入意外的副作用。此外,MVI 有助于避免 MVVM 中的常見問題,例如“回調(diào)地獄”和“狀態(tài)爆炸”。

當(dāng)然,從 MVVM 遷移到 MVI 存在一些挑戰(zhàn),例如需要重構(gòu)現(xiàn)有代碼以及學(xué)習(xí)新的概念和模式。然而,通過仔細(xì)的規(guī)劃、清晰的文檔和徹底的測試,MVI 的好處可以遠(yuǎn)遠(yuǎn)超過成本。通過采用像 MVI 這樣的反應(yīng)式和可預(yù)測的架構(gòu),您可以創(chuàng)建更可靠、可擴(kuò)展和可維護(hù)的 Android 應(yīng)用程序,以滿足用戶和利益相關(guān)者的需求。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容