在學習一個技術之前,我們首先要搞清為什么要用它、用它以后會有什么好處,這樣我們才能有興趣的學習下去,
一、為什么要用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的也很多,大家也可以作為參考,
小生才疏學淺,文中必有遺漏和錯誤,十分歡迎閱讀過的同學指正,大家一起討論!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/186490.html
標籤:其他
