关注个人简介,技术不迷路~
从模型-视图-视图模型 (MVVM) 架构迁移到模型-视图-意图 (MVI) 架构似乎是一项艰巨的任务。但凭借更清晰的架构和更可预测的应用程序行为的好处,这是一次非常值得付出努力的转变。
在本文中,我们将探讨 MVVM 和 MVI 之间的差异,并提供有关如何迁移到 MVI 的指导。
MVVM 与 MVI
MVVM 架构是移动应用程序开发中广泛使用的模式。它将用户界面(View)与数据和逻辑(ViewModel)分开,并允许两个组件之间进行数据绑定。ViewModel 负责为 View 准备数据并处理用户输入。
另一方面,MVI 架构是近年来流行的一种较新的模式。它还将视图和数据分开,但添加了一个称为意图的新层,该层负责以结构化且可预测的方式表示用户操作。Intent 被传递给模型,模型产生一个新的状态,然后显示在视图中。
两种架构之间的主要区别在于,在 MVVM 中,ViewModel 负责用户操作和更新视图状态。在 MVI 中,意图是一个代表用户操作的独立层,可以更轻松地推断应用程序行为并处理边缘情况。
为什么选择 MVI?
1.更好的关注点分离: 使用MVI,Intent层负责用户操作,Model层负责状态管理,View层负责状态渲染。这种分离使得推断应用程序行为以及对应用程序进行更改变得更加容易,而不会影响架构的其他部分。
2. 更可预测的应用程序行为: 使用 MVI,应用程序的状态始终由单个数据对象表示,这使得更容易推理和预测应用程序的行为。这种可预测性可以减少错误并提供更好的用户体验。
3. 提高可测试性: MVI 使编写单元测试变得更加容易,因为每一层都可以独立测试。通过架构的可预测数据流使得编写涵盖所有可能状态和边缘情况的测试变得更加容易。
如何从 MVVM 迁移到 MVI?
从 MVVM 迁移到 MVI 似乎是一项艰巨的任务,但重要的是要记住这是一个渐进的过程。以下是一些需要考虑的步骤:
- 了解MVI架构: 在进行切换之前,请确保您了解MVI的关键概念,包括Intent层和单向数据流。
- 识别组件: 仔细查看现有的 MVVM 代码并识别需要更改的组件。这包括 ViewModel、View 以及任何数据模型或存储库。
- 创建 Intent 层:将 Intent 层添加到您的应用程序中,该层以结构化且可预测的方式表示用户操作。该层应该与 ViewModel 和 Model 分开。
- 更新 ViewModel: 修改您的 ViewModel 以接受 Intent 并将其传递给模型。ViewModel 不应再负责更新 View 的状态。
- 更新模型: 修改模型以根据意图和当前状态生成新状态。模型不应再负责处理用户输入。
- 更新视图: 修改视图以呈现模型提供的状态。视图不应再负责获取数据或更新状态。
- *****为架构的每一层* **编写单元测试,以确保数据流可预测,并覆盖所有可能的状态和边缘情况。****
从 MVVM 迁移到 MVI 的实施主要步骤
第 1 步:创建 Intent 类
sealed class MyIntent {
object LoadData : MyIntent()
data class UpdateData(val newData: Data) : MyIntent()
object DeleteData : MyIntent()
}
第2步:修改ViewModel
修改您的 ViewModel 以接受意图并将其传递给模型。ViewModel 不应再负责更新 View 的状态。
class MyViewModel ( private val myModel: MyModel) : ViewModel() {
private val _state = MutableLiveData()
val state: LiveData = _state
fun processIntent (intent: MyIntent ) {
val newState = myModel.processIntent(intent, _state.value)
_state.postValue(newState)
}
}
第三步:创建State类
创建一个表示应用程序当前状态的类,例如:
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步:修改视图
修改视图以呈现模型提供的状态。视图不应再负责获取数据或更新状态。
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
}
}
结论
总之,从 MVVM 迁移到 MVI 可以为您的 Android 应用带来多项好处。通过采用 MVI 架构,您可以创建更具反应性、可预测性和可测试性的应用程序,同时减少层之间的耦合并提高代码库的整体可维护性。
MVI 允许您将用户交互建模为意图,根据这些意图更新应用程序的状态,然后在 UI 中呈现该状态。这使得您可以更轻松地推断应用程序中的数据流,并更改代码,而不会引入意外的副作用。此外,MVI 有助于避免 MVVM 中的常见问题,例如“回调地狱”和“状态爆炸”。
当然,从 MVVM 迁移到 MVI 存在一些挑战,例如需要重构现有代码以及学习新的概念和模式。然而,通过仔细的规划、清晰的文档和彻底的测试,MVI 的好处可以远远超过成本。通过采用像 MVI 这样的反应式和可预测的架构,您可以创建更可靠、可扩展和可维护的 Android 应用程序,以满足用户和利益相关者的需求。