介绍完背景以及初衷之后,我们开始搭建MVVM的框架,这一部分我们进行简单的搭建,了解MVVM架构的基本结构。
创建新项目
首先创建一个新的项目,在根目录下创建一个config.gradle如图
config.gradle用于配置项目中各种lib引用和版本号控制/**
* config.gradle用于配置项目中各种lib引用和版本号控制
*
* [module_*] 各module版本号及applicationId控制
* 如需在各个module中升级更新版本号,请使用 module_[modulename]*的命名规则
*
* [project.ext.dependVersion] 中创建各个依赖库的版本号控制,需在类库名称后增加‘_version’
*
* [类库maven地址] 中创建各个类库的maven地址,同一类库需要引用多个类时,可以使用数组,要确保类库引用不重复
*
* [项目依赖列表] 中创建可以直接让module引用的依赖列表,以Deps结尾,原则上以类库功能分类,比如网络库,图片处理库
* 尽量不要以类库本身的名字命名依赖列表
*
* 各个module中引用类库时尽量使用项目依赖列表中的项目,不要直接使用类库地址中的项目
*
* 需要添加新的类库时,先查询本列表和项目中是否已引用类似功能的类库,尽量不要添加重复功能的类库
*/
project.ext {
compileSdkVersion = 27
buildToolsVersion = '27.0.3'
minSdkVersion = 16
targetSdkVersion = 27
//主app
module_appApplicationId = 'yang.cehome.com.mvvmdemo'
module_appVersionCode = 0001
module_appVersionName = '1.0.0'
module_appName = 'MVVM'
//引用类库的版本号
dependVersion = [
kotlin_version : '1.2.51',
support_version: '27.1.1'
]
//*************************类库maven地址**************************
kotlin_base = [kotlin_stdlib_jdk8: "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$dependVersion.kotlin_version"]
supportLibs = [
design : "com.android.support:design:$dependVersion.support_version",
appcompat_v7: "com.android.support:appcompat-v7:$dependVersion.support_version",
constraint : 'com.android.support.constraint:constraint-layout:1.1.3']
//********************项目依赖列表**********************
kotlinDeps = [kotlin_base.values()]
supportDeps = [supportLibs.values()]
}
复制代码
然后再build.gradle我们引用相应的library库
使用的时候需要注意的地方依赖方法
AndroidStudio升级到3.0之后,gradle版本也随之升级到了3.0.0版本。 在这之后,大家可能注意依赖的方式发生了一些变化,在这里简单介绍一下
写在前面
现在MVC MVP MVVM框架的介绍很多,网上一搜一大堆就不着重介绍了。 之前用MVP重新写的框架,但是也遇到了很多不方便的地方,所以这次我们着重介绍MVVM框架 这里开始使用kotlin,并遵循google的App开发架构指南,才找到一种较好的构建MVVM应用程序的方式 首先:什么是MVVM? MVVM是Model-View-ViewModel的简写,是有别于MVC和MVP的另一种架构模式。 相比于MVP,MVVM没有多余的回调,利用Databinding框架就可以将ViewModel中的数据绑定到UI上,从而让开发者只需要更新ViewModel中的数据,就可以改变UI。
再来讲一下分别的作用 ● Model层:负责提供数据源给ViewModel,包含实体类,网络请求和本地存储等功能 ● ViewModel:将Model层提供的数据根据View层的需要进行处理,通过DataBinding绑定到相应的UI上 ● View:Activity、Fragment、layout.xml、Adapter、自定义View等等,负责将三者联系起来。
另一个好处就是可以做单元测试,纯的kotlin代码写着再舒服不过,而且可以保证数据的正确性。相比于run app需要十几秒或者几分钟、十几分钟,run 一次单元测试是以毫秒记的,效率是很可观的。
代码实现
首先我们创建一个类
/**
* @author yangzc
* @data 2018/9/6 13:58
* @desc
*
*/
class Onclick(val who: String, val count: Int)
复制代码
以前我们写一个点击事件的代码大概
布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="yang.cehome.com.mvvmdemo.MainActivity">
<Button
android:id="@+id/bt_onclick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="onclick"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
复制代码
在Activity当中是这么实现的
package yang.cehome.com.mvvmdemo
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val onclik = Onclick("my", 0)
tv_count.text = "${onclik.who}点击了${onclik.count}次"
bt_onclick.setOnClickListener(View.OnClickListener {
onclik.count++
tv_count.text = "${onclik.who}点击了${onclik.count}次"
})
}
}
复制代码
就实现了我们平时经常写的一段点击事件并且显示的一段代码 然而 我们要用MVVM框架显然就不是这么写的了 首先我们看一下架构
根据我们的这个结构图 我们简单阐述一下 各个模块的作用Model层:负责提供数据源给ViewModel,包含实体类,网络请求和本地存储等功能 ViewModel层:将Model层提供的数据根据View层的需要进行处理,通过DataBinding绑定到相应的UI上 View层:Activity、Fragment、layout.xml、Adapter、自定义View等等,负责将三者联系起来 简单的介绍了一下MVVM之后,创建项目之后,看一下结构
基础Demo
下面我们就根据我们之前说的简单写一个Demo 首先看一下包的结构 DataBindingUtil.setContentView 这个函数做了三步操作:
- inflate操作,创建布局文件对应的view对像
- setContentView操作,将view加入window
- bind操作,创建ActivityXxxBinding 对像 bind操作最终调用了ActivityXxxBinding.bind(view, bindingComponent)操作,然后调用了: new ActivityXxxBinding(bindingComponent, view) 创建了ActivityXxxBinding 对像。 //启用数据绑定 dataBinding{ enabled = true } 我们看看布局文件 其实 我们可以看到在MVVM当中布局文件的作用有所加强,不仅仅是构造一个UI效果。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<!--需要的viewModel,通过mBinding.vm=mViewMode注入-->
<variable
name="vm"
type="yang.cehome.com.mvvmdemo.viewmodel.OnclikViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.MainActivity">
<Button
android:id="@+id/bt_onclick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{()->vm.click()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="来点一下试试" />
<TextView
android:id="@+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:text="@{vm.info}"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="点了0次" />
</android.support.constraint.ConstraintLayout>
</layout>
复制代码
值得注意的几点:
1.最外层增加layout标签 2.增加了一个data标签 这个标签是我们的ViewModel通过绑定注入的 3.在每个控件上增加相应的方法 下面看看M层的代码 提供给ViewModel层的数据
package yang.cehome.com.mvvmdemo.model
/**
* @author yangzc
* @data 2018/9/6 13:58
* @desc 数据源Model(MVVM 中的V),负责提供ViewModel中需要处理的数据
*
*/
class Onclick(val who: String, var count: Int)
复制代码
下面我们在看看ViewModel层 这里主要承担了数据处理功能 并负责提供给View层数据 ViewModel是用来存储和管理UI相关的数据。
package yang.cehome.com.mvvmdemo.viewmodel
import android.databinding.ObservableField
import yang.cehome.com.mvvmdemo.model.Onclick
/**
* @author yangzc
* @data 2018/9/6 16:59
* @desc 处理数据V(MVVM 中的VM),负责提供View中需要处理的数据
*
*/
class OnclikViewModel(val onlick: Onclick) {
/******data******/
val info = ObservableField<String>("\"${onlick.who}点击了${onlick.count}次\"")
/******binding******/
fun click() {
onlick.count++
info.set("\"${onlick.who}点击了${onlick.count}次\"")
}
}
复制代码
最后我们看看View层,也就是我们Activity和Fragment
package yang.cehome.com.mvvmdemo.view
import android.databinding.DataBindingUtil
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import yang.cehome.com.mvvmdemo.R
import yang.cehome.com.mvvmdemo.databinding.ActivityMainBinding
import yang.cehome.com.mvvmdemo.model.Onclick
import yang.cehome.com.mvvmdemo.viewmodel.OnclikViewModel
/**
* MVVM 当中的一个V层 将三者联系起来
*/
class MainActivity : AppCompatActivity() {
private lateinit var mBinding: ActivityMainBinding
private lateinit var mViewMode: OnclikViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
/model
val onclick = Onclick("me", 0)
///ViewModel
mViewMode = OnclikViewModel(onclick)
///binding
mBinding.vm = mViewMode
}
}
复制代码
以上就是一个简单的MVVM的框架