前言
Android
开发倒退到明天曾经相当成熟了,各种架构大家也都耳熟能详,如 MVC
,MVP
,MVVM
等,其中 MVVM
更是被官网举荐,成为 Android
开发中的显学。
不过软件开发中没有银弹,MVVM
架构也不是尽如人意的,在应用过程中也会有一些不太不便之处,而 MVI
能够很好的解决一部分 MVVM
的痛点。
本文次要包含以下内容
MVC
,MVP
,MVVM
等经典架构介绍MVI
架构到底是什么?MVI
架构实战
须要重点指出的是, 题目中说
MVI
架构是MVVM
的进阶版是指MVI
在MVVM
十分类似,并在其根底上做了肯定的改进,并不是说MVI
架构肯定比MVVM
适宜你的我的项目
各位同学能够在剖析比拟各个架构后,抉择适合我的项目场景的架构
经典架构介绍
MVC
架构介绍
MVC
是个古老的 Android
开发架构,随着 MVP
与MVVM
的风行曾经逐步退出历史舞台,咱们在这里做一个简略的介绍, 其架构图如下所示:
MVC
架构次要分为以下几局部
- 视图层(
View
):对应于xml
布局文件和java
代码动静view
局部 - 管制层(
Controller
):次要负责业务逻辑,在android
中由Activity
承当,同时因为XML
视图性能太弱,所以Activity
既要负责视图的显示又要退出管制逻辑,承当的性能过多。 - 模型层(
Model
):次要负责网络申请,数据库解决,I/O
的操作,即页面的数据起源
因为 android
中xml
布局的功能性太弱,Activity
实际上负责了 View
层与 Controller
层两者的工作,所以在 android
中mvc
更像是这种模式:
因而 MVC
架构在 android
平台上的次要存在以下问题:
Activity
同时负责View
与Controller
层的工作,违反了繁多职责准则Model
层与View
层存在耦合,存在相互依赖,违反了最小常识准则
MVP
架构介绍
因为 MVC
架构在 Android
平台上的一些缺点,MVP
也就应运而生了, 其架构图如下所示:
MVP
架构次要分为以下几个局部
View
层:对应于Activity
与XML
, 只负责显示UI
, 只与Presenter
层交互,与Model
层没有耦合Presenter
层:次要负责解决业务逻辑,通过接口回调View
层Model
层:次要负责网络申请,数据库解决等操作,这个没有什么变动
咱们能够看到,MVP
解决了 MVC
的两个问题,即 Activity
承当了两层职责与 View
层与 Model
层耦合的问题
但 MVP
架构同样有本人的问题
Presenter
层通过接口与View
通信,实际上持有了View
的援用- 然而随着业务逻辑的减少,一个页面可能会非常复杂,这样就会造成
View
的接口会很宏大。
MVVM
架构介绍
MVVM
模式将 Presenter
改名为 ViewModel
,基本上与 MVP
模式完全一致。
惟一的区别是,它采纳双向数据绑定(data-binding
):View
的变动,主动反映在 ViewModel
,反之亦然 MVVM
架构图如下所示:
能够看出 MVVM
与MVP
的次要区别在于, 你不必去被动去刷新 UI
了,只有 Model
数据变了,会主动反映到 UI
上。换句话说,MVVM
更像是自动化的MVP
。
MVVM
的双向数据绑定次要通过 DataBinding
实现,不过置信有很多人跟我一样,是不喜爱用 DataBinding
的,这样架构就变成了上面这样
View
察看ViewModle
的数据变动并自我更新, 这其实是繁多数据源而不是双向数据绑定,所以其实MVVM
的这一大个性我其实并没有用到View
通过调用ViewModel
提供的办法来与ViewMdoel
交互
小结
MVC
架构的次要问题在于Activity
承当了View
与Controller
两层的职责,同时View
层与Model
层存在耦合MVP
引入Presenter
层解决了MVC
架构的两个问题,View
只能与Presenter
层交互,业务逻辑放在Presenter
层MVP
的问题在于随着业务逻辑的减少,View
的接口会很宏大,MVVM
架构通过双向数据绑定能够解决这个问题MVVM
与MVP
的次要区别在于, 你不必去被动去刷新UI
了,只有Model
数据变了,会主动反映到UI
上。换句话说,MVVM
更像是自动化的MVP
。MVVM
的双向数据绑定次要通过DataBinding
实现,但有很多人 (比方我) 不喜爱用DataBinding
,而是View
通过LiveData
等察看ViewModle
的数据变动并自我更新, 这其实是繁多数据源而不是双向数据绑定
MVI
架构到底是什么?
MVVM
架构有什么有余?
要理解 MVI
架构,咱们首先来理解下 MVVM
架构有什么有余
置信应用 MVVM
架构的同学都有如下教训,为了保障数据流的单向流动,LiveData
向外裸露时须要转化成 immutable
的,这须要增加不少模板代码并且容易忘记,如下所示
class TestViewModel : ViewModel() {
// 为保障对外裸露的 LiveData 不可变,减少一个状态就要增加两个 LiveData 变量
private val _pageState: MutableLiveData<PageState> = MutableLiveData()
val pageState: LiveData<PageState> = _pageState
private val _state1: MutableLiveData<String> = MutableLiveData()
val state1: LiveData<String> = _state1
private val _state2: MutableLiveData<String> = MutableLiveData()
val state2: LiveData<String> = _state2
//...
}
如上所示,如果页面逻辑比较复杂,ViewModel
中将会有许多全局变量的 LiveData
, 并且每个LiveData
都必须定义两遍,一个可变的,一个不可变的。这其实就是我通过 MVVM
架构写比较复杂页面时最好受的点。
其次就是 View
层通过调用 ViewModel
层的办法来交互的,View
层与 ViewModel
的交互比拟扩散,不成体系
小结一下,在我的应用中,MVVM
架构次要有以下有余
- 为保障对外裸露的
LiveData
是不可变的,须要增加不少模板代码并且容易忘记 View
层与ViewModel
层的交互比拟扩散零乱,不成体系
MVI
架构是什么?
MVI
与 MVVM
很类似,其借鉴了前端框架的思维,更加强调数据的单向流动和惟一数据源, 架构图如下所示
其次要分为以下几局部
Model
: 与MVVM
中的Model
不同的是,MVI
的Model
次要指UI
状态(State
)。例如页面加载状态、控件地位等都是一种UI
状态View
: 与其余MVX
中的View
统一,可能是一个Activity
或者任意UI
承载单元。MVI
中的View
通过订阅Model
的变动实现界面刷新Intent
: 此Intent
不是Activity
的Intent
,用户的任何操作都被包装成Intent
后发送给Model
层进行数据申请
单向数据流
MVI
强调数据的单向流动,次要分为以下几步:
- 用户操作以
Intent
的模式告诉Model
Model
基于Intent
更新State
View
接管到State
变动刷新 UI。
数据永远在一个环形构造中单向流动,不能反向流动:
下面简略的介绍了下 MVI
架构,上面咱们一起来看下具体是怎么应用 MVI
架构的
MVI
架构实战
总体架构图
咱们应用 ViewModel
来承载 MVI
的Model
层,总体构造也与 MVVM
相似, 次要区别在于 Model
与View
层交互的局部
Model
层承载UI
状态,并暴露出ViewState
供View
订阅,ViewState
是个data class
, 蕴含所有页面状态View
层通过Action
更新ViewState
,代替MVVM
通过调用ViewModel
办法交互的形式
MVI
实例介绍
增加 ViewState
与ViewEvent
ViewState
承载页面的所有状态,ViewEvent
则是一次性事件,如 Toast
等, 如下所示
data class MainViewState(val fetchStatus: FetchStatus, val newsList: List<NewsItem>)
sealed class MainViewEvent {data class ShowSnackbar(val message: String) : MainViewEvent()
data class ShowToast(val message: String) : MainViewEvent()}
- 咱们这里
ViewState
只定义了两个,一个是申请状态,一个是页面数据 ViewEvent
也很简略,一个简略的密封类,显示Toast
与Snackbar
ViewState
更新
class MainViewModel : ViewModel() {private val _viewStates: MutableLiveData<MainViewState> = MutableLiveData()
val viewStates = _viewStates.asLiveData()
private val _viewEvents: SingleLiveEvent<MainViewEvent> = SingleLiveEvent()
val viewEvents = _viewEvents.asLiveData()
init {emit(MainViewState(fetchStatus = FetchStatus.NotFetched, newsList = emptyList()))
}
private fun fabClicked() {
count++
emit(MainViewEvent.ShowToast(message = "Fab clicked count $count"))
}
private fun emit(state: MainViewState?) {_viewStates.value = state}
private fun emit(event: MainViewEvent?) {_viewEvents.value = event}
}
如上所示
- 咱们只需定义
ViewState
与ViewEvent
两个State
, 后续减少状态时在data class
中增加即可,不须要再写模板代码 ViewEvents
是一次性的,通过SingleLiveEvent
实现,当然你也能够用Channel
当来实现- 当状态更新时,通过
emit
来更新状态
View
监听ViewState
private fun initViewModel() {viewModel.viewStates.observe(this) {renderViewState(it)
}
viewModel.viewEvents.observe(this) {renderViewEvent(it)
}
}
如上所示,MVI
应用 ViewState
对 State
集中管理,只须要订阅一个 ViewState
便可获取页面的所有状态,绝对 MVVM
缩小了不少模板代码。
View
通过 Action
更新State
class MainActivity : AppCompatActivity() {private fun initView() {
fabStar.setOnClickListener {viewModel.dispatch(MainViewAction.FabClicked)
}
}
}
class MainViewModel : ViewModel() {fun dispatch(action: MainViewAction) =
reduce(viewStates.value, action)
private fun reduce(state: MainViewState?, viewAction: MainViewAction) {when (viewAction) {is MainViewAction.NewsItemClicked -> newsItemClicked(viewAction.newsItem)
MainViewAction.FabClicked -> fabClicked()
MainViewAction.OnSwipeRefresh -> fetchNews(state)
MainViewAction.FetchNews -> fetchNews(state)
}
}
}
如上所示,View
通过 Action
与ViewModel
交互,通过 Action
通信,有利于 View
与 ViewModel
之间的进一步解耦,同时所有调用以 Action
的模式汇总到一处,也有利于对行为的集中剖析和监控
总结
本文次要介绍了 MVC
,MVP
,MVVM
与MVI
架构,目前 MVVM
是官网举荐的架构,但依然有以下几个痛点
MVVM
与MVP
的次要区别在于双向数据绑定,但因为很多人 (比方我) 并不喜爱应用DataBindg
,其实并没有应用MVVM
双向绑定的个性,而是繁多数据源- 当页面简单时,须要定义很多
State
, 并且须要定义可变与不可变两种, 状态会以双倍的速度收缩,模板代码较多且容易忘记 View
与ViewModel
通过ViewModel
裸露的办法交互,比拟零乱难以保护
而 MVI
能够比拟好的解决以上痛点,它次要有以下劣势
- 强调数据单向流动,很容易对状态变动进行跟踪和回溯
- 应用
ViewState
对State
集中管理,只须要订阅一个ViewState
便可获取页面的所有状态,绝对MVVM
缩小了不少模板代码 ViewModel
通过ViewState
与Action
通信,通过浏览ViewState
和Aciton
定义就能够理清ViewModel
的职责,能够间接拿来作为接口文档应用。
当然 MVI
也有一些毛病,比方
- 所有的操作最终都会转换成
State
,所以当简单页面的State
容易收缩 state
是不变的,因而每当state
须要更新时都要创立新对象代替老对象,这会带来肯定内存开销
软件开发中没有银弹,所有架构都不是完满的,有本人的实用场景, 读者可依据本人的需要抉择应用。
但通过以上的剖析与介绍,我置信应用 MVI
架构代替没有应用 DataBinding
的MVVM
是一个比拟好的抉择~
相干视频举荐:
【2021 最新版】Android studio 装置教程 +Android(安卓)零基础教程视频(适宜 Android 0 根底,Android 初学入门)含音视频_哔哩哔哩_bilibili
Android 架构设计原理与实战——Jetpack 联合 MVP 组合利用开发一个优良的 APP!_哔哩哔哩_bilibili
Android 进阶必学:jetpack 架构组件—Navigation_哔哩哔哩_bilibili
Android 进阶零碎学习——Jetpack 先天优良的基因能够防止数据内存透露_哔哩哔哩_bilibili