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: 在MVIView作为接口,可以在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 的关键实力

  1. 单向循环的数据流
  2. 易于捕捉和修复bug
  3. 易于代码测试
  4. 在不需要单元测试的情况下,拥有测试整个app全部层级的能力

7. MVI是如何工作的

用户进行的一个动作,将会被转变为一个Intent–> Intent将会是一种状态,作为输入传递给Model–>Model存储状态,并将状态请求发送到View–> ViewModel中加载状态 --> 显示给用户。

如果我们观察到,数据将会从用户开始,并通过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 架构简介

Android MVI 架构简介

Android Jetpack系列之MVI架构

Android MVI架构解析以及与其他架构对比

对应用架构的理解与 MVI 介绍

Android MVI 架构学习