关于android:MVVM-进阶版MVI-架构了解一下

8次阅读

共计 5999 个字符,预计需要花费 15 分钟才能阅读完成。

前言

Android开发倒退到明天曾经相当成熟了,各种架构大家也都耳熟能详,如 MVC,MVP,MVVM 等,其中 MVVM 更是被官网举荐,成为 Android 开发中的显学。
不过软件开发中没有银弹,MVVM架构也不是尽如人意的,在应用过程中也会有一些不太不便之处,而 MVI 能够很好的解决一部分 MVVM 的痛点。
本文次要包含以下内容

  1. MVC,MVP,MVVM等经典架构介绍
  2. MVI架构到底是什么?
  3. MVI架构实战

须要重点指出的是, 题目中说 MVI 架构是 MVVM 的进阶版是指 MVIMVVM十分类似,并在其根底上做了肯定的改进,并不是说 MVI 架构肯定比 MVVM 适宜你的我的项目
各位同学能够在剖析比拟各个架构后,抉择适合我的项目场景的架构

经典架构介绍

MVC架构介绍

MVC是个古老的 Android 开发架构,随着 MVPMVVM的风行曾经逐步退出历史舞台,咱们在这里做一个简略的介绍, 其架构图如下所示:

MVC架构次要分为以下几局部

  1. 视图层(View):对应于 xml 布局文件和 java 代码动静 view 局部
  2. 管制层(Controller):次要负责业务逻辑,在 android 中由 Activity 承当,同时因为 XML 视图性能太弱,所以 Activity 既要负责视图的显示又要退出管制逻辑,承当的性能过多。
  3. 模型层(Model):次要负责网络申请,数据库解决,I/O的操作,即页面的数据起源

因为 androidxml布局的功能性太弱,Activity实际上负责了 View 层与 Controller 层两者的工作,所以在 androidmvc更像是这种模式:

因而 MVC 架构在 android 平台上的次要存在以下问题:

  1. Activity同时负责 ViewController层的工作,违反了繁多职责准则
  2. Model层与 View 层存在耦合,存在相互依赖,违反了最小常识准则

MVP架构介绍

因为 MVC 架构在 Android 平台上的一些缺点,MVP也就应运而生了, 其架构图如下所示:

MVP架构次要分为以下几个局部

  1. View层:对应于 ActivityXML, 只负责显示 UI, 只与Presenter 层交互,与 Model 层没有耦合
  2. Presenter层:次要负责解决业务逻辑,通过接口回调 View
  3. Model层:次要负责网络申请,数据库解决等操作,这个没有什么变动

咱们能够看到,MVP解决了 MVC 的两个问题,即 Activity 承当了两层职责与 View 层与 Model 层耦合的问题

MVP 架构同样有本人的问题

  1. Presenter层通过接口与 View 通信,实际上持有了 View 的援用
  2. 然而随着业务逻辑的减少,一个页面可能会非常复杂,这样就会造成 View 的接口会很宏大。

MVVM架构介绍

MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。
惟一的区别是,它采纳双向数据绑定(data-binding):View的变动,主动反映在 ViewModel,反之亦然
MVVM架构图如下所示:

能够看出 MVVMMVP的次要区别在于, 你不必去被动去刷新 UI 了,只有 Model 数据变了,会主动反映到 UI 上。换句话说,MVVM更像是自动化的MVP

MVVM的双向数据绑定次要通过 DataBinding 实现,不过置信有很多人跟我一样,是不喜爱用 DataBinding 的,这样架构就变成了上面这样

  1. View察看 ViewModle 的数据变动并自我更新, 这其实是繁多数据源而不是双向数据绑定,所以其实 MVVM 的这一大个性我其实并没有用到
  2. View通过调用 ViewModel 提供的办法来与 ViewMdoel 交互

小结

  1. MVC架构的次要问题在于 Activity 承当了 ViewController两层的职责,同时 View 层与 Model 层存在耦合
  2. MVP引入 Presenter 层解决了 MVC 架构的两个问题,View只能与 Presenter 层交互,业务逻辑放在 Presenter
  3. MVP的问题在于随着业务逻辑的减少,View的接口会很宏大,MVVM架构通过双向数据绑定能够解决这个问题
  4. MVVMMVP 的次要区别在于, 你不必去被动去刷新 UI 了,只有 Model 数据变了,会主动反映到 UI 上。换句话说,MVVM更像是自动化的MVP
  5. 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架构次要有以下有余

  1. 为保障对外裸露的 LiveData 是不可变的,须要增加不少模板代码并且容易忘记
  2. View层与 ViewModel 层的交互比拟扩散零乱,不成体系

MVI架构是什么?

MVIMVVM 很类似,其借鉴了前端框架的思维,更加强调数据的单向流动和惟一数据源, 架构图如下所示

其次要分为以下几局部

  1. Model: 与 MVVM 中的 Model 不同的是,MVIModel 次要指 UI 状态(State)。例如页面加载状态、控件地位等都是一种 UI 状态
  2. View: 与其余 MVX 中的 View 统一,可能是一个 Activity 或者任意 UI 承载单元。MVI中的 View 通过订阅 Model 的变动实现界面刷新
  3. Intent: 此 Intent 不是 ActivityIntent,用户的任何操作都被包装成 Intent 后发送给 Model 层进行数据申请

单向数据流

MVI强调数据的单向流动,次要分为以下几步:

  1. 用户操作以 Intent 的模式告诉Model
  2. Model基于 Intent 更新State
  3. View接管到 State 变动刷新 UI。

数据永远在一个环形构造中单向流动,不能反向流动:

下面简略的介绍了下 MVI 架构,上面咱们一起来看下具体是怎么应用 MVI 架构的

MVI架构实战

总体架构图

咱们应用 ViewModel 来承载 MVIModel层,总体构造也与 MVVM 相似, 次要区别在于 ModelView层交互的局部

  1. Model层承载 UI 状态,并暴露出 ViewStateView订阅,ViewState是个data class, 蕴含所有页面状态
  2. View层通过 Action 更新 ViewState,代替MVVM 通过调用 ViewModel 办法交互的形式

MVI实例介绍

增加 ViewStateViewEvent

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()}
  1. 咱们这里 ViewState 只定义了两个,一个是申请状态,一个是页面数据
  2. ViewEvent也很简略,一个简略的密封类,显示 ToastSnackbar

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}
}

如上所示

  1. 咱们只需定义 ViewStateViewEvent两个 State, 后续减少状态时在data class 中增加即可,不须要再写模板代码
  2. ViewEvents是一次性的,通过 SingleLiveEvent 实现,当然你也能够用 Channel 当来实现
  3. 当状态更新时,通过 emit 来更新状态

View监听ViewState

    private fun initViewModel() {viewModel.viewStates.observe(this) {renderViewState(it)
        }
        viewModel.viewEvents.observe(this) {renderViewEvent(it)
        }
    }

如上所示,MVI 应用 ViewStateState 集中管理,只须要订阅一个 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通过 ActionViewModel交互,通过 Action 通信,有利于 ViewViewModel 之间的进一步解耦,同时所有调用以 Action 的模式汇总到一处,也有利于对行为的集中剖析和监控

总结

本文次要介绍了 MVC,MVP,MVVMMVI架构,目前 MVVM 是官网举荐的架构,但依然有以下几个痛点

  1. MVVMMVP 的次要区别在于双向数据绑定,但因为很多人 (比方我) 并不喜爱应用 DataBindg,其实并没有应用MVVM 双向绑定的个性,而是繁多数据源
  2. 当页面简单时,须要定义很多State, 并且须要定义可变与不可变两种, 状态会以双倍的速度收缩,模板代码较多且容易忘记
  3. ViewViewModel 通过 ViewModel 裸露的办法交互,比拟零乱难以保护

MVI 能够比拟好的解决以上痛点,它次要有以下劣势

  1. 强调数据单向流动,很容易对状态变动进行跟踪和回溯
  2. 应用 ViewStateState集中管理,只须要订阅一个 ViewState 便可获取页面的所有状态,绝对 MVVM 缩小了不少模板代码
  3. ViewModel通过 ViewStateAction通信,通过浏览ViewStateAciton 定义就能够理清 ViewModel 的职责,能够间接拿来作为接口文档应用。

当然 MVI 也有一些毛病,比方

  1. 所有的操作最终都会转换成 State,所以当简单页面的State 容易收缩
  2. state是不变的,因而每当 state 须要更新时都要创立新对象代替老对象,这会带来肯定内存开销

软件开发中没有银弹,所有架构都不是完满的,有本人的实用场景, 读者可依据本人的需要抉择应用。
但通过以上的剖析与介绍,我置信应用 MVI 架构代替没有应用 DataBindingMVVM是一个比拟好的抉择~

相干视频举荐:

【2021 最新版】Android studio 装置教程 +Android(安卓)零基础教程视频(适宜 Android 0 根底,Android 初学入门)含音视频_哔哩哔哩_bilibili

Android 架构设计原理与实战——Jetpack 联合 MVP 组合利用开发一个优良的 APP!_哔哩哔哩_bilibili

Android 进阶必学:jetpack 架构组件—Navigation_哔哩哔哩_bilibili

Android 进阶零碎学习——Jetpack 先天优良的基因能够防止数据内存透露_哔哩哔哩_bilibili

正文完
 0