介绍完背景以及初衷之后, 我们开始搭建 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 的框架
项目地址
https://github.com/yang0range/MVVM
来源: http://www.jianshu.com/p/6a5a9803d03b