介紹完背景以及初衷之後,我們開始搭建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的框架