Android MVI 架构简介
Posted microhex
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MVI 架构简介相关的知识,希望对你有一定的参考价值。
翻译来自 Medium :
https://medium.com/@soundhar.p03/android-mvi-architecture-230cd30e40b4
大家有时间和精力可以阅读原文,翻译可能不怎么到位,到时候网批评指正。
大家好,在本篇博客中,我们就会讨论有关Andorid的MVI设计模式。近些日子有关Andorid架构模式都在逐步进化中。对于我们开发的App中,我们开始面临新的挑战和困难。新的设计模式将会被发现来解决类似的问题。
作为Andorid开发人员,我们已经拥有了MVC、MVP和MVVM作为最流行和熟知的开发模式,但是这些开发模式都是使用命令式编程方法。通过这种方法,大部分面临的挑战都可以得到解决,但是我们依然会面临一些挑战,比如线程安全、应用状态的维持等等问题。通过这种,我们来看看MVI
架构模式是什么,它是如何解决这些挑战的,然后如何来开始MVI
.
这里,来聊一下需要做的动作.
文章目录
1. Android设计模式预览
Android Framework层提供了大量的灵活的实现,来让你随心所欲的组织和创建自己的App。
这种自由是很有价值的,但是它也可以导致程序拥有大量的类,不一致的命令方案,同时也将造成架构不匹配或者缺失。
这种类型的失误将会对App的测试、维护、扩展造成很大的不便。所以,大多人就有了传统的Model-View-Controller(MVC)模式,或者Model-View-Presenter(MVP)模式,或者Model-View—ViewModel(MVVM)模式。
2. 列举现存的设计模式
3. MVI架构模式
MVI
表示的是Model
-View
-Intent
.这个模式最近才被引入Android。受到Cycle.js
框架的思路影响,是基于单向圆柱流的原理进行工作的。
Model
:不像其它架构模式的Model
,在MVI
架构中Model
表示UI
的状态。举个例子,UI
可能会存在不同的状态,比如数据加载Data Loading
,加载完成Loaded
,用户的动作造成数据的改变
,错误
,用户当前屏幕位置状态
等等,每一个状态都被存储到Model
对象中。
View
: 在MVI
中View
作为接口,可以在Activity
或者Fragment
中实现。这个接口的意思就是需要有一个容器来接收不同状态并进行展示。它们使用可观察的Intent
(这里的Intent
并不是传统的Android Intent,这里应该取Intent的本意,意图)来回应用户的动作。
Intent
: 这个并不是之前所提到的Android Intent
.用户的动作的结果作为输入值传递给Intent
。回过来,我们可以说,我们将会发送Models
作为输入给Intent
,然后通过View
加载这些Model
的状态。
4. MVI数据流
我们可以通过下面的图表来理解MVI
数据流的走向。
用户接口始终连接View
, 我们上面讲过,数据的加载方式是通过Intent将用户的动作作为输入值发送给Model, 然后Model的变使得View
展现形式发生改变。
5. 为什么需要 MVI
你可能会考虑到这个新模式的使用方法,即使我们在Android开发过程中使用了多种架构。
当应用在扩张,未知的功能需要被添加时,没有明确的状态管理,视图(View)的渲染和业务逻辑可能会变得有些混乱。
代码的可扩展性越高,新的想法和更新就可以越灵活。扩展性、灵活性和更易于测试,这就是MVI
架构可以为我们提供的优势。
6. MVI 的关键实力
- 单向循环的数据流
- 易于捕捉和修复bug
- 易于代码测试
- 在不需要单元测试的情况下,拥有测试整个app全部层级的能力
7. MVI是如何工作的
用户进行的一个动作,将会被转变为一个Intent
–> Intent
将会是一种状态,作为输入传递给Model
–>Model
存储状态,并将状态请求发送到View
–> View
从Model
中加载状态 --> 显示给用户。
如果我们观察到,数据将会从用户开始,并通过Intent
到用户结束.不能通过其它的方式。
因此这种叫做单向
架构,如果用户做相同的动作,那么就重复相同的循环。因此它是循环的:
8. MVI的优势
- 对于架构来说,维护状态不再是那么困难的事情了。它主要做的就是状态维护;
- 因为数据流是单向的,所以可以很容易的被跟踪和预测;
- 它确保线程是安全的,因为状态对象是不可变的;
- 容易进行Debug,当错误发生时,我们可以知道对象的状态;
- 更加的解耦,每个组件专注自己的业务和逻辑;
- app的测试将会很容易,我们可以将不同的业务逻辑映射为状态。
9. MVI的劣势
- 每一个用户的动作来维护一个状态,可能会导致大量的模版代码。
- 对于所有的状态,必须创建大量的对象;这样对app的管理会成本比较高。
- 处理一个警告的状态可能会比较困难,因为我们可能会更改配置。举个例子,如果没有网络,我们要在
snackBar
上显示,对于配置的更改,snackBar
将会重新显示。就可用性而言,这里必须处理。
10. 项目代码
对于项目的代码,可以点击这里.
对于代码,这里列举了一下:
与我们有关的差不多就是MainIntent
,MainState
了。这里主要讲一下这个项目的逻辑:
页面初始状态 | 页面加载状态 | 页面正常状态 | 页面数据错误状态 |
---|---|---|---|
这里的四种状态,如果按照MVI
的逻辑,使用代码可以描述为:
sealed class MyMainState
// 空闲状态
object Idle : MyMainState()
// 加载状态
object Loading : MyMainState()
// 加载存在数据
data class MyMainUser(val dataList : List<User>) : MyMainState()
// 存在异常逻辑
data class MyError(val errorInfo : String) : MyMainState()
那么对应的State
,对应的View
的处理为:
when(it)
is MyMainState.Idle -> //空闲
is MyMainState.Loading -> //加载
recyclerView.visibility = View.GONE
buttonFetchUser.visibility = View.GONE
progressBar.visibility = View.VISIBLE
is MyMainState.MyMainUser -> // 存在数据
recyclerView.visibility = View.VISIBLE
buttonFetchUser.visibility = View.GONE
progressBar.visibility = View.GONE
showUserListWithData(it.dataList)
is MyMainState.MyError -> // 错误页面
recyclerView.visibility = View.GONE
progressBar.visibility = View.GONE
buttonFetchUser.visibility = View.VISIBLE
Toast.makeText(this@MyMainActivity, it.errorInfo, Toast.LENGTH_LONG).show()
那么State
有了,我们需要的Intent
在哪里呢?其实我们可以这么理解,切换页面显示就是用户的一个Intent
,但是Intent
中存在我们定义的4种不同的State
。
用户,也就是我们的View
通过发送这样一个Intent
,来告之我们需要切换页面了,至于页面需要切换成什么,那么就需要内部通过State
确定了。
具体的数据流转,大家可以下载代码查看一下就行了,个人感觉应该算是MVVM的一个改进版,或者形象一点就是将State
做了进一步的封装,有好处也有坏处了。
对于初学者,这个项目里面已经做了一些简化,当然,我们可以优化这个项目来提高水平。
我希望你可以学到Android中MVI的架构。
保持学习,保持探索,保持成长。
谢谢。
以上是关于Android MVI 架构简介的主要内容,如果未能解决你的问题,请参考以下文章
Android真的推荐用MVI模式?MVI和MVVM有啥区别?