MVVM最新學(xué)習(xí)心得

前言

在前幾年興起了MVVM架構(gòu)設(shè)計(jì)模式,最具有代表的框架就是DataBinding,雖然這種設(shè)計(jì)架構(gòu)非常新穎,但是在使用中仍然還有很多痛點(diǎn),所以我當(dāng)時(shí)覺得短時(shí)間這個(gè)設(shè)計(jì)架構(gòu)可能不會(huì)太流行。

最近接手了新項(xiàng)目,使用的就是MVVM,才發(fā)現(xiàn)只一兩年的功夫MVVM的發(fā)展竟然這么快,已經(jīng)是Android開發(fā)者必備的技能之一了。

正文

DataBinding在剛開始階段,最令我頭疼的就是數(shù)據(jù)處理的問題,往往為了顯示數(shù)據(jù),我要在XML中綁定N多個(gè)字段,如果是一個(gè)中等以上的工程,還有更蛋疼的問題,例如:

  • 你的XML可能迫切的需要if或者switch這樣的判斷;
  • 意想不到的空指針

在2018年,Google推出JetPack庫,其中的ViewModel+LIveData終于把MVVM推上了新的高度。

ViewModel

使用ViewModel需要依賴lifecycle庫:

implementation "android.arch.lifecycle:viewmodel:x.x.x"
implementation "android.arch.lifecycle:extensions:x.x.x"

ViewModel的創(chuàng)建方法主要有兩種:

// 獲取FragmentActivity共享的ViewModel
ViewModelProviders.of(FragmentActivity).get(ViewModel::class.java)

// 獲取FragmentActivity共享的ViewModel
ViewModelProviders.of(Fragment).get(ViewModel::class.java)

ViewModel的共享范圍主要有兩種:一種是FragmentActivity,一種是Fragment,可以根據(jù)自己的需要選擇共享的范圍。如果你想要一個(gè)Application級(jí)別的ViewModel,目前是不支持的,你可以自定義Application持有一個(gè)ViewModel,或者使用單例模式。

ViewModel解決的問題

1、擴(kuò)大數(shù)據(jù)共享的應(yīng)用場(chǎng)景。

一般的數(shù)據(jù)共享是Activity與Fragment的數(shù)據(jù)傳遞,傳統(tǒng)做法是使用setArguments(Bundle),這種方法有以下弊端:

  • 可能無法預(yù)測(cè)setArguments會(huì)在Fragment的哪個(gè)周期完成,要進(jìn)行異常判斷;
  • setArguments中的數(shù)據(jù)可能會(huì)發(fā)現(xiàn)改變,如果是Activity直接設(shè)置Fragment的數(shù)據(jù),耦合性很高;
  • 數(shù)據(jù)較多時(shí),F(xiàn)ragment會(huì)有很多的變量,影響可讀性和維護(hù)性。

使用ViewModel,可以避免以上的尷尬情況,需要什么數(shù)據(jù)就從ViewModel中?。?/p>

  • 新加數(shù)據(jù)傳遞,不用修改Activity的setArguments代碼,F(xiàn)ragment也不用編寫數(shù)據(jù)接收的方法;
  • 減少數(shù)據(jù)傳遞,不必考慮是否要?jiǎng)h除暫時(shí)無用的代碼;
  • 取數(shù)據(jù)時(shí),請(qǐng)注意數(shù)據(jù)的有效性,做好判斷即可;

除此之外,自定義View也可以得到ViewModel,這樣某些功能耦合性非常強(qiáng)的自定義View開發(fā)更加便捷。不過需要注意的是View的context的上下文是Activity類型(不會(huì)是Fragment)的,所以只能使用Activity級(jí)別的數(shù)據(jù)共享。

2、解決DataBinding的視圖顯示問題。

如果視圖的顯示需要很多的數(shù)據(jù),那么XML就會(huì)變得越來越臃腫,并且迫切需要添加一些簡單的判斷,例如:

如果A為空就顯示B,如果B為空就先是C,如果是C為空...

雖然DataBinding支持三元運(yùn)算符,能夠滿足if判斷的需要,但是很顯然在XML維護(hù)邏輯要比Java或者Kotlin要困難的多(無拼寫錯(cuò)誤提示等)。所以我們非常需要把部分代碼從XML分離出來,ViewModel就非常適合擔(dān)任這個(gè)角色。

修改前:

<?xml version="1.0" encoding="utf-8"?>
<layout>
    
    <data>
        
        <variable
                name="A"
                type="String" />

        <variable
                name="B"
                type="String" />

        <variable
                name="C"
                type="String" />
        
        
    </data>

     <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:maxLines="4"
                android:ellipsize="middle"
                android:text="A != null ? A : B != null ? B : C" />
    ...
    
</layout>

修改后:

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>

        <variable
                name="viewModel"
                type="ViewModel" />

    </data>

    <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:maxLines="4"
                android:ellipsize="middle"
                android:text="@{viewModel.getShowContent()}" />
...

</layout>

LiveData

剛才我們已經(jīng)討論了ViewModel的用法,但是還有一個(gè)問題沒有解決,那就是數(shù)據(jù)更新的問題,解決這個(gè)問題的最佳方式就是觀察者模式,但是如果沒有處理好觀察者的注冊(cè)和解綁很容易出現(xiàn)內(nèi)存溢出。LiveData就可以完美的解決這個(gè)問題。

我們需要添加LiveData的依賴:

implementation "androidx.lifecycle:lifecycle-livedata:2.1.0"

下面是一個(gè)簡單的示例:

// 名為openDrawer的Boolean類型的LiveData
public final MutableLiveData<Boolean> openDrawer = new MutableLiveData<>();

// 更新openDrawer 
openDrawer.setValue(true)

// 觀察openDrawer 的值的變化
openDrawer.observe(this, aBoolean -> {
             Toast.makeText(this, "${aBoolean}", Toast.LENGTH_SHORT).show();
        });

LiveData的子類是MutableLiveData,內(nèi)部有value屬性保存最新的值,訂閱LiveData的變化,直接調(diào)用LiveData.observe():

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
owner:注冊(cè)的周期,會(huì)在owner銷毀的時(shí)候,解綁觀察者。
observer:觀察的值發(fā)生變化的回調(diào)函數(shù)

owner直接使用Activity或者Fragment即可。如果你還不了解Lifecycle的使用,可以查看一下相關(guān)的資料。

總結(jié)

最后我畫了一張架構(gòu)圖,總結(jié)了一下最新的MVVM的使用架構(gòu):

MVVM架構(gòu)圖

Activity:處理UI問題,但是應(yīng)當(dāng)盡量避免這樣做,盡量統(tǒng)一使用DataBinding。
ViewModel:保存頁面需要的數(shù)據(jù),功能復(fù)雜的話可以拆分成多個(gè)。
DataBinding:處理UI視圖,持有ViewModel做數(shù)據(jù)展示。如果頁面功能比較復(fù)雜,可以對(duì)ViewModel和DataBinding再次細(xì)分。

如果大家對(duì)MVVM有更棒的理解,歡迎留言共同學(xué)習(xí)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容