一篇文章彻底弄懂Android-MVVM

在学习一个技术之前,我们首先要搞清为什么要用它、用它以后会有什么好处,这样我们才能有兴趣的学习下去。

一、为什么要用MVVM?

我为什么要用这个什么MVVM,我就平常写和它有什么不同吗?

首先我们要说一下,使用MVVM后,程序会有哪些变化:

1.MVVM并不会提升程序的性能,甚至如果用不好还会降低性能。

2.MVVM会增大代码的总量。

3.阅读MVVM的代码你必须不停的跳来跳去,跳到你恶心想吐。

啥?你在搞笑吗?那我为什么还要用它?且慢,我还没说最重要的一条。

4.MVVM将让你的程序完全解耦。当然,是正确使用的前提下。

为了最后这一条,我们用前3条的牺牲完全不过分,真正写代码的时候,我们面对的往往不是性能的些许提升,也不是几十或几百K的包大小增大带来的问题,而是程序不停迭代所带来的程序稳定性要求。而这也是MVVM大显身手的地方,MVVM能够完全让你的业务功能组件化,让我们需要什么就调什么,并且组件可以在不同页面之间复用;在写业务组件的时候,我们可以完全集中精力,只管写组件要完成的功能,而无需分神它顾。

读到这,相信你应该对MVVM稍微有点兴趣了吧。

二、MVVM到底是什么?

MVVM,是Model、View、ViewModel三者的缩写,它是一种程序的设计框架,是一种设计思路。不同的人实现MVVM,所用的构成技术、实现以后的性能都是不一样的。千万不要觉得它有多深奥,他其实就是由一系列代码(或技术)构成的一个程序的底座。我们在良好底座上开发出来的程序稳定性更高,可扩展性更强。

下面我们挨个来来说Model、View、ViewModel。

1.Model:数据提供。

Model在程序中专门用于提供数据,不管是网络请求获得的数据,还是数据库获得的数据,统统写在Model里。Model层独立性相当强,它只用来提供数据,而不管数据是用来做什么的。

2.View:视图元素和视图元素初始化。

View在Android中指代的就是我们常见的布局文件和Activity中的元素初始化部分。总之,所有一切我们在Android上肉眼能看见的东西都是View。在View层里,我只对UI做初始化,比如将TextView设置字体大小,为Banner控件设置滚动速度等等,这些大多可以直接在布局文件中完成。

3.ViewModel:操作业务数据,并将数据呈现在View上。

ViewModel根据业务需要,从Model层调取相关数据,然后更新View层相关元素。

说起来有点抽象,别急,下面我们用一个简单的例子来解释它们怎样互相配合,你很快就会明白。

在例子中,我们使用Google提供的DataBinding技术来完成数据绑定,以实现View和ViewModel层的交互。

【🌰时间】

例子非常非常简单,一个仓库管理的页面,一共三个元素,其中更新时间和仓库物品列表是从服务器动态获取的。

平常写的话,我们会在Activity内完成所有的操作,先进行网络请求,得到数据后为TextView设置文字、为RecycleView设置Adapter。但使用了MVVM后,代码将被拆分为三个部分,我们按View、ViewModel、Model的顺序直接上代码,随后在一一解释:


View层:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="stockViewModel"
            type="com.ben.shop.viewmodel.StockManagementViewModel" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/white"
            android:gravity="center"
            android:padding="@dimen/dp_5"
            android:text="仓库管理系统"
            android:textStyle="bold" />
            
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dp_10"
            android:gravity="center"
            android:text="@{stockViewModel.bindingData.component2()}"
            android:textColor="@color/red"
            android:textSize="@dimen/sp_15" />
            
        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:stockGoodsViewLoader="@{stockViewModel.bindingData.component1()}" />
    </LinearLayout>

</layout>

ViewModel层:

class StockManagementViewModel(mvvmViewModel: MVVMViewModel?) : BaseViewModel(mvvmViewModel) {

    fun load() {
        val newData = getModel(StockModel::class.java).getStockList()
        val time = getModel(StockModel::class.java).getUpdateTime()
        bindingData.data.clear()
        bindingData.data.addAll(newData)
        bindingData.updateTime = "更新时间:${time}"
        bindingData.notifyChange()
    }

    override fun onResumed() {
        super.onResumed()
        load()
    }

    val bindingData: BindingData = BindingData(mutableListOf(), "")

    data class BindingData(
            @Bindable val data: MutableList<StockGood>,
            @Bindable var updateTime: String
    ) : BaseObservable()
}

@BindingAdapter("android:stockGoodsViewLoader")
fun stockGoodsViewLoader(recyclerView: RecyclerView, data: List<StockGood>) {
    recyclerView.apply {
        layoutManager = LinearLayoutManager(recyclerView.context).apply {
            orientation = LinearLayoutManager.VERTICAL
        }
        adapter = StockManagementAdapter(recyclerView.context, data)
    }
}

Model层:

class StockModel(mvvmModel: MVVMModel?) : HttpModel(mvvmModel) {

    fun getStockList(): List<StockGood> {
        return mutableListOf<StockGood>().apply {
            add(StockGood("1", "钳子", 3))
            add(StockGood("2", "扳手", 12))
        }
    }

    fun getUpdateTime(): String {
        return Utils.DateUtil.getCurrentlyTimeByFormatter(Constant.DateFormat4)
    }

}

View层在我们这个例子中只有一个布局文件,布局文件是DataBinding的标准写法,在标签中写好控件需要的ViewModel。

<data>
        <variable
            name="stockViewModel"
            type="com.ben.shop.viewmodel.StockManagementViewModel" />
</data>

然后将TextView和RecyclerView与ViewModel中的元素绑定好。

android:text="@{stockViewModel.bindingData.component2()}"
android:stockGoodsViewLoader="@{stockViewModel.bindingData.component1()}"

View没看明白没关系,先来看ViewModel。

还记得ViewModel的作用吗,我来重复一遍:它从Model层获取数据,然后更新视图。

这里ViewModel实现了Activity的生命周期函数,onResumed是ViewModel开始执行的地方

调用Model获取数据:

        val newData = getModel(StockModel::class.java).getStockList()
        val time = getModel(StockModel::class.java).getUpdateTime() 

更新视图

        bindingData.data.clear()
        bindingData.data.addAll(newData)
        bindingData.updateTime = "更新时间:${time}"
        bindingData.notifyChange()

这里注意, notifyChange方法是BaseObservable中的方法,用于通知视图刷新

因为我们已经在View层将数据绑定到了data和updateTime两个变量上,因此,我们只需要更新这两个变量,就可以完成View层视图的刷新,这也正是MVVM强大的地方。从这里就可以看出,View层和ViewModel层是高度解耦的,只通过两个变量相互关联,这样,ViewModel就有了非常高的独立性,可以轻而易举的被其他View调用,也可以从例子中的View层瞬间剔除,就像插上或拔出一个U盘那样简单。

Model层比较容易理解,由于只是一个例子,我们在这里并没有请求网络,实际开发过程中,你只需要使用你想使用的网络工具请求网络或调用数据库,获取到数据后返回给ViewModel层即可。

这里值得一题的是Activity中的代码:

class StockManagementActivity : MVVMActivity<ActibityStockManagementBinding>() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentViewByDataBinding(R.layout.actibity_stock_management)
        dataBinding.stockViewModel = getViewModel(StockManagementViewModel::class.java)
    }
}

可以看到,Activity中几乎没有逻辑代码,仅仅有一行来实例化ViewModel。MVVM就这样,将业务逻辑完整从Activity中拆分为独立的三块,不仅解放了Activity,更使整个代码的逻辑清晰,可读性极强,并且功能块之间互不干扰,这也就实现了我们开头所说的组件化开发。

三、总结

怎么样,MVVM还不错吧?如果您曾经了解过MVC、MVP,相信本文一定很容易理解,MVVM只不过的它们的“升级版”,实现过程不同,目标却是相同的。这些设计思想并不是十分深奥的东西,本质就是让软件质量变得更好,如果不明白它们的原理,不仅不会让代码质量提高,反而会使程序变得不知所云,得不偿失。

另外说一下,本文主讲MVVM,DataBinding的用法和原理没有过多涉及,但相信看过本文以后,您应该对它也有了一定的了解了吧。我开头说过,MVVM实现的技术各不相同。DataBinding是Goodle出品,并且Android Studio中支持的相当不错,因此被我采用。在了解了MVVM的机制以后,你完全可以选择你想使用的技术,构建你自己的MVVM框架。如果各位有兴趣,我可以写一个关于DataBinding的文章。当然网络上关于DataBinding的也很多,大家也可以作为参考。

小生才疏学浅,文中必有遗漏和错误,十分欢迎阅读过的同学指正,大家一起讨论!

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值