<Android>架构MV<T>

228 阅读3分钟

总结和记录Android架构模式

前言

long long ago,写Android代码就是都堆到Activity中,充其量会封装一些方法放到其他的类里,来使得Activity看起来没那么臃肿;这样写对于很简单的页面当然没有问题,但复杂的页面即便封装了一些,Activity类依然十分臃肿(相信大部分人都见过老项目上千行的Activity类吧)。
为了解决这种问题,让代码更合理、职责更明确、扩展更容易,因此使用架构模式,来帮助我们更好的实现项目。

MVC

Android中的角色划分
model数据相关(数据库、接口数据)
viewxml\activity
controllerxxController\activity

image.png 上图,是较为主流的MVC实现。虽然较非架构编码职责更清晰,降低了耦合,但重点是Model层与View层是有关联的,Model会持有View的引用,并且Activity在控制层面和view层面仍有一些耦合。
为了解决activity内部耦合问题,实现模视分离,便有了MVP。

MVP

Android中的角色划分
model数据相关(数据库、接口数据)
viewxml\activity
presenterxxPresenter

image.png

上图,是MVP实现。由此可见,跟MVC是大致上相同的,区别在于实现了模视分离,职责更加清晰,仅通过Presenter这个中间商,串联起View和Model。在代码层面上,其实就是面向接口编程,通过IPresenter定义好操作函数;因此也会暴露出,如果逻辑过多时,接口会变得较为复杂,Presenter类也会变得复杂

MVVM

Android中的角色划分
model数据相关(数据库、接口数据)
viewxml\activity
viewmodelxxViewModel

image.png 上图,是MVVM实现。这里的ViewModel并非指jetpack组件。MVVM架构的重点就是双向绑定,通过DataBinding实现。这样进一步实现解耦,不需要我们自己再实现接口通知视图改变,视图改变后也会自动改变缓存数据。其缺点就是使用了DataBinding后,较难维护,而且出现问题较难定位。也因此大多数项目中还是采用了ViewBinding。

MVI

Android中的角色划分
modelUI状态、数据相关(数据库、接口数据)
viewxml\activity
intent用户意图

image.png 上图,是我认为的MVI实现。
图中内圈(红框黑字)部分,是cycle.js中的MVI架构,这也是MVI的来源。通过对其文档的了解,再类比到android MVI实现,能够辅助理解这种架构思想。

关键词:
响应式编程、界面状态、用户行为事件、数据单向流动、数据模型驱动界面、Google推荐的应用架构

代码相关实现:

data class MyViewState(
    val content: String = "等待",
    val pageStatus: PageStatus = PageStatus.Success
)

/**
 * 界面的事件 如弹出toast,弹出dialog
 */
sealed class MyViewEvent {
    data class ShowToast(val message: String) : MyViewEvent()
}

/**
 * 界面的状态,加载中,成功,失败
 */
sealed class PageStatus {
    object Loading : PageStatus()
    object Success : PageStatus()
    data class Error(val throwable: Throwable) : PageStatus()
}

/**
 * action 行为
 */
sealed class MyViewAction {
    object FirstRequest : MyViewAction()
}
/**
 * DEMO
 * @author :curry
 * @date   :2022/1/13
 */
class MyViewModel : ViewModel() {
    private val _viewStates = MutableLiveData(MyViewState())
    val viewStates = _viewStates.asLiveData()
    private val _viewEvents: SingleLiveEvents<MyViewEvent> = SingleLiveEvents()
    val viewEvents = _viewEvents.asLiveData()

    /**
     * 匹配对应的行为,做对应的事儿
     */
    fun dispatch(viewAction: MyViewAction) {
        when (viewAction) {
            is MyViewAction.FirstRequest -> firstRequest()
        }
    }

    private fun firstRequest() {
        /**
         * 将操作的结果以界面应该呈现的状态返回
         * 界面应该处理的操作如弹出框、toast定义为event 按event返回
         */
        viewModelScope.launch {
                _viewStates.setState {copy(pageStatus = PageStatus.Loading) }
                delay(2000)
                _viewStates.setState {copy(content = it, pageStatus = PageStatus.Success) }
                _viewEvents.setEvent(NetworkViewEvent.ShowToast(it))
                delay(2000)
                _viewStates.setState {copy(pageStatus = PageStatus.Error(it))}
        }
    }
}
/**
 * DEMO
 * @author :curry
 * @date   :2022/1/13
 */
class MyActivity : AppCompatActivity() {
    private val viewModel by viewModels<MyViewModel>()
...
    private fun initViewModel() {
        /**
         * 监听状态,做对应的UI展现
         */
        viewModel.viewStates.let { state ->
            state.observeState(this, MyViewState::pageStatus) {
                when (it) {
                    is PageStatus.Success -> //showContent()
                    is PageStatus.Loading -> //showLoading()
                    is PageStatus.Error ->   //showError()
                }
            }
        }

        viewModel.viewEvents.observeEvent(this) {
            when (it) {
                is MyViewEvent.ShowToast -> toast(it.message)
            }
        }
    }

    /**
     * 用户的点击事件,转成定义的Action,发给viewmodel
     */
    fun simpleRequest(view: View) {
        viewModel.dispatch(MyViewAction.FirstRequest)
    }
}

参考:

其他参考

Android 开发中的架构模式 -- MVC / MVP / MVVM