个人对MVVM模式理解和介绍

368 阅读4分钟

个人对MVVM模式理解和介绍

MVVM由以下三个部分组成

  • Model
    • JavaBean
    • DataSource
  • View
    • Layout Xml
    • View、ViewGroup、Activity、Fragment的View功能
  • ViewModel
    • DataBinding自动生成的对象
    • AndroidViewModel的子类
    • View、ViewGroup、Activity、Fragment的统筹管理功能

MVVM是Model+View+ViewModel的简写,是一种代码架构模式。

Model

Model层主要包含两个内容JavaBean和DataSource

JavaBean

JavaBean就是传统的数据类,实现简单的get set方法。在不需要set方法的时候,不要创建set方法。Kotlin可以忽视

DataSource

DataSource是数据的来源,这个类用单例的方式来获取。因为使用单例模式能很好的在Application运行的过程中获取需要的数据,下面是例子。

class XXXDataSource private constructor(val context: Application) {
   
    companion object {
        private var INSTANCE: XXXDataSource? = null

        @JvmStatic
        fun getInstance(context: Application): XXXDataSource {
            return INSTANCE ?: XXXDataSource(context).apply { INSTANCE = this }
        }
    }

全局属性通常申明需要长期保存或者需要跨页面多次使用的针对Application的全局对象,比如用户数据。

方法的部分主要是和服务器进行数据获取,或者是和本地的数据缓存进行交互。比如RemoteGetData(远程获取数据),CacheGetData(内存缓存数据),DatabaseGetData(数据库获取数据)

class XXXDataSource private constructor(val context: Application) {
    //用户数据
    var userInfo: UserInfo? = null
    var getUserInfoAsync(callback:callback){
        if(userInfo!=null){
            callback.back(userInfo)//内存缓存数据
        }else {
            val info:UserInfo?=getLocalData()//Database数据,或者shareference数据
            if(info!=null){
                callback.back(userInfo)
            }else{
                getUserInfoRemote(callback)//网络获取数据
            }
        }
    }
}

View

包含Layout Xml和View、ViewGroup、Activity、Fragment的View功能

Layout Xml

通过DataBinding的处理Layout Xml其实变成了一种可以编辑的代码,不仅仅只是布局最开始的状态了,而是可以配合数据变化而进行变化的。具体用法参照网络上DataBinding的参考文档和各种使用的工程

View、ViewGroup、Activity、Fragment的View功能

这个是我个人的理解。 其实Activity和Fragment有生命周期,而且需要在这个进行View的更改,所以是又有View的功能,又有ViewModel的功能,耦合性是比较高的。简单来说就是在这些里面,只操作View的变化,不要管数据如何获取,有点像MVP中的V层的作用,但是不需要写基础接口,耦合性其实更低,而且更灵活。

ViewModel

ViewModel层包含DataBinding自动生成的对象、AndroidViewModel、View、ViewGroup、Activity、FragmentActivity的统筹管理功能

DataBinding自动生成的类

这些类是自动生成的,而生成和xml的编写有关系,或者是写了一些自定义的DataBinding的xml属性,使用就行了.

AndroidViewModel

AndroidViewModel是Google针对MVVM架构而专门推出的一个基类,ViewModel可以用在多个Activity,Fragment中。比如手机获取验证码这种功能,就可以重复多个页面里使用。

在AndroidViewModel中,需要用Observable对象(不是rx的Observable)和xml中的View绑定,来通知数据的更改。或者使用LiveEvent在Activity或者Fragment中注册,来进行一些Toast,Snackbar,Dialog的显示。

MVVM-N和MVVM-L

MVVM-N和MVVM-L是我针对MVVM的两种理解的扩展,并不是对MVVM模式的基础架构的变更,这个L表示的是Listener,N表示Navigator。

具体理解是,View层和ViewModel需要进行点击交互的时候,比如Activity点一个按钮,ViewModel进行数据请求,当ViewModel获取到数据后需要返还给Activity进行页面跳转。我们可以使用LiveEvent进行注册。但是有些使用LiveEvent满足不了这个需求。总会遇到这种问题。

L模式

L是在Layout Xml中声明的Listener接口,和ViewModel是同一层级的

    <layout>
        <data>
            <variable
            name="listener"
            type="UserListener" />
            <variable
            name="viewModel"
            type="UserViewModel" />
        <data>
        <Button 
            android:onClick="{(view)->listener.click(view)}"/>
    </layout>

然后在Activity的代码中,去调用ViewModel的方法

class UserActivity:AppcompatActivity(),UserListener{
    fun onCreate(bundle:Bundle){
        val viewModel=...
    }
    fun click(view:View){
        //show某个dialog,dialog点击确认后才能调用ViewModel的方法
        viewModel.click(/*异步的话这里需要传一个回调*/)
    }
}

N模式

N是让Activity实现Navigator接口,然后把这个Navigator对象传给ViewModel

    class UserActivity:AppcompatActivity(),UserNavigator{
    //UserNavigator有个方法是click
        fun onCreate(bundle:Bundle){
            val viewModel=...
            viewModel.navigator=this
        }
        fun click(){
            //show某个dialog,dialog点击确认后才能调用ViewModel的方法
            viewModel.click(/*异步的话这里需要传一个回调*/)
        }
    }
    <layout>
        <data>
            <variable
            name="viewModel"
            type="UserViewModel" />
        <data>
        <Button 
            android:onClick="{(view)->viewModel.click()}"/>
    </layout>
    class UserViewModel(app:Application):AndroidViewModel(app){
        val navigator:UserNavigator?=null
        fun click(){
            navigator.click()
        }
    }

就我个人的理解而言,我更喜欢MVVM-L的方式。当然,也可以使用LiveEvent注册的方式来处理某些dialog的显示。具体的话,还是看使用场景