前言
??廢話少說(shuō)颊亮,直接上點(diǎn)干貨柴梆。https://github.com/yiweituoxie/MyKotlin ,代碼結(jié)構(gòu)如下圖
??這是一個(gè)簡(jiǎn)單介紹在MVVM框架下使用RxJava2+Retrofit2請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)的小項(xiàng)目终惑,接下來(lái)我會(huì)不斷地在這個(gè)項(xiàng)目上更新一些平時(shí)用到的好用的特性或者功能绍在,同時(shí)也會(huì)發(fā)布對(duì)應(yīng)的文章。首先要聲明的是雹有,這篇文章和這個(gè)項(xiàng)目暫時(shí)是針對(duì)MVVM的初學(xué)者或者剛開(kāi)始使用MVVM的同學(xué)的偿渡,所以有大篇幅都在介紹官方的或者是針對(duì)項(xiàng)目的代碼進(jìn)行說(shuō)明。
??平常用習(xí)慣MVP的同學(xué)也可以在我的github上找到一個(gè)相對(duì)比較成熟的MVP項(xiàng)目霸奕,歡迎交流與push https://github.com/yiweituoxie/Mvp-Kotlin
??想要更加詳細(xì)地了解MVVM或者M(jìn)VP的同學(xué)可以轉(zhuǎn)彎到官方https://github.com/googlesamples/android-architecture?utm_source=tuicool
官方的Sample中不但介紹了MVVM的兩種實(shí)現(xiàn)(LiveData溜宽,DataBinding),同時(shí)也向開(kāi)發(fā)者提供了一些非常好用的類质帅,例如SingleLiveEvent适揉。
MVVM劇情介紹
??為了不落俗套,我在這邊就跳過(guò)故事的背景介紹煤惩,想要了解MVVM框架的可以移步到https://www.zhihu.com/question/30976423/answer/50224601嫉嘀。故事的梗概就是記述我們的大偵探夏洛克ViewModel幫助他的兩個(gè)委托人Model組織和View組織找到各自的成員在對(duì)方組織里面的另一半的故事,那如果是這樣的故事魄揉,又怎么能區(qū)分這不是波洛的故事而是福爾摩斯的故事呢剪侮,對(duì),你沒(méi)猜錯(cuò)洛退,華生在最新一季的MVVM中票彪,閃亮登場(chǎng)了。事實(shí)上不狮,在這一季之前,MVVM中在旱,我們看到夏洛克ViewModel辦案非常費(fèi)勁摇零,在很多觀眾的代碼前,時(shí)常要深入到M和V里面桶蝎,插手本來(lái)不屬于它的事務(wù)驻仅,這也讓很多新來(lái)的觀眾一頭霧水谅畅,說(shuō)好的解耦呢,說(shuō)好的分離呢噪服,說(shuō)好的效率呢毡泻。對(duì)MVVM的口碑可以說(shuō)分歧很大,有不少新來(lái)的觀眾紛紛棄劇粘优。在收視率的壓力下仇味,導(dǎo)演兼編劇Google推出新角色華生LiveData可以說(shuō)是眾望所歸。
??網(wǎng)上有相當(dāng)多介紹LiveData和ViewModel的文章雹顺,可以說(shuō)是五花八門琳瑯滿目丹墨,其中不乏優(yōu)秀的影評(píng),但是很多新老觀眾總結(jié)起來(lái)都表示挺暈的嬉愧,其實(shí)不妨看看導(dǎo)演自己怎么介紹角色贩挣。在Google的官網(wǎng)上對(duì)LiveData有詳細(xì)的介紹:
??LiveData屬于android.arch.lifecycle:livedata-core這個(gè)包下面的一個(gè)類,包名已經(jīng)很顯然地表明没酣,LiveData本身是和內(nèi)存回收有關(guān)的王财。第一句話,LiveData是一個(gè)可以在給定生命周期內(nèi)觀察到的數(shù)據(jù)持有者類裕便,沒(méi)錯(cuò)绒净,非常官方,后面緊接著是LiveData的內(nèi)部原理闪金,其實(shí)翻譯成好理解一點(diǎn)的話(并不嚴(yán)謹(jǐn))疯溺,就是LiveData可以綁定多個(gè)觀察者,并且會(huì)跟隨觀察者的生命周期存活哎垦,當(dāng)活動(dòng)觀察者的數(shù)量在0和1之間發(fā)生變化時(shí)囱嫩,可以得到通知。而在最后一段漏设,則直截了當(dāng)?shù)卣f(shuō)墨闲,它和ViewModel的親密關(guān)系。
??翻開(kāi)ViewModel的介紹郑口,作為一個(gè)大名鼎鼎的Class鸳碧,竟然在自己的個(gè)人空間里面,直接了當(dāng)?shù)脭[明了和LiveData關(guān)系犬性,可以說(shuō)是男友力Max:
??“ViewModel通常通過(guò)LiveData或Android DataBinding公開(kāi)這些信息”瞻离,事實(shí)上,有相當(dāng)多的人還在使用AndroidDataBinding乒裆,而用過(guò)的人套利,我相信都或多或少感受到它的不方便,對(duì)于有代碼潔癖的小伙伴來(lái)說(shuō),設(shè)置有點(diǎn)膈應(yīng)肉迫。所以照顧到大家得感受验辞,官網(wǎng)只貼出了ViewModel和LiveData的合影,作為官方認(rèn)證的CP喊衫,觀眾還要說(shuō)啥跌造,高舉起來(lái),舔就完事了族购。
public class UserActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_activity_layout);
final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);
viewModel.userLiveData.observer(this, new Observer() {
@Override
public void onChanged(@Nullable User data) {
// update ui.
}
});
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewModel.doAction();
}
});
}
}
public class UserModel extends ViewModel {
public final LiveData<User> userLiveData = new LiveData<>();
public UserModel() {
// trigger user load.
}
void doAction() {
// depending on the action, do necessary business logic calls and update the
// userLiveData.
}
}
??上面的代碼可以說(shuō)是相當(dāng)?shù)鼐?jiǎn)壳贪,在UserActivity中,viewModel的userLiveData綁定到UserActivity上联四,當(dāng)調(diào)用可以發(fā)現(xiàn)viewModel的doAction方法改變userLiveData的值是撑碴,userLiveData會(huì)自動(dòng)通知它的觀察者(也就是UserActivity):“我變了,你要不要做點(diǎn)事情”〕眨可以看到醉拓,ViewModel里是并沒(méi)有View的任何邏輯或?qū)ο蠓椒ǎ峭ㄟ^(guò)定義LiveData收苏,通知LiveData的觀察者亿卤。相信你很容易就能推理得出,開(kāi)發(fā)者可以在任意的View(界面)上使用UserModel鹿霸,比如說(shuō)登錄界面排吴,注冊(cè)界面,用戶管理界面等等懦鼠,只需要監(jiān)聽(tīng)界面關(guān)心的數(shù)據(jù)就可以了钻哩。這也就是ViewModel的復(fù)用性和低耦合的優(yōu)點(diǎn)。
我的小劇場(chǎng)
??小劇場(chǎng)是一個(gè)簡(jiǎn)單的登錄界面肛冶,麻雀雖小街氢,但五臟俱全,開(kāi)篇的時(shí)候已經(jīng)介紹過(guò)了睦袖,代碼是基于RxJava2+Retrofit2進(jìn)行網(wǎng)絡(luò)請(qǐng)求的珊肃,正是如此,ViewModel需要通知View的信息就包括馅笙,正在請(qǐng)求伦乔,請(qǐng)求成功和請(qǐng)求失敗三種信息。所以在ViewModel中董习,定義了三個(gè)LiveData烈和,分別是userInfo,loadingMessage皿淋,toastStringMessage斥杜,分別保存請(qǐng)求成功的用戶信息虱颗,是否正在請(qǐng)求,異常信息蔗喂,并且在對(duì)應(yīng)的方法中修改它們的值。
??對(duì)應(yīng)的高帖,我們需要在View(LoginActivity)中創(chuàng)建一個(gè)ViewModel的實(shí)例缰儿,當(dāng)然少不了的,就是對(duì)關(guān)心的LiveData綁定觀察者散址,也就是View本身乖阵。
??為什么要一再?gòu)?qiáng)調(diào)是關(guān)心的LiveData呢?這也正是上面提到過(guò)的復(fù)用性和低耦合了预麸,舉個(gè)簡(jiǎn)單的例子瞪浸,在用戶管理界面,使用同樣一個(gè)UserModel進(jìn)行數(shù)據(jù)的獲取吏祸,但是這個(gè)時(shí)候加載用戶的信息对蒲,首先會(huì)獲取本地保存的信息,同時(shí)為了保證數(shù)據(jù)的一致性贡翘,還會(huì)獲取服務(wù)器的用戶信息(比如在其它地方修改過(guò)用戶的信息)蹈矮。出于對(duì)UX的考慮,等待框是不會(huì)出現(xiàn)的鸣驱,只需要默默地同步信息就可以了泛鸟。那么,在用戶管理界面踊东,就并不需要監(jiān)聽(tīng)loadingMessage北滥。
?? 這其實(shí)也側(cè)面地說(shuō)明了,View和ViewModel的關(guān)系是多對(duì)多的闸翅,也就是View中可以有多個(gè)ViewModel再芋,ViewModel也可以被多個(gè)View綁定。
多說(shuō)兩句
??細(xì)心的同學(xué)可能已經(jīng)留意到同樣是被監(jiān)聽(tīng)的數(shù)據(jù)缎脾,loadingMessage 繼承自MutableLiveData祝闻,而 toastStringMessage則繼承前言提到過(guò)的 SingleLiveEvent。這究竟是出于什么考慮呢遗菠?
class LoadingMessage : MutableLiveData<Boolean>()
class ToastStringMessage : SingleLiveEvent<String>() {
override fun setValue(t: String?) {
super.setValue(t)
super.setValue(null)
}
override fun postValue(t: String?) {
super.postValue(t)
super.postValue(null)
}
}
??這里就涉及到更加規(guī)范的ViewModel和LiveData的使用联喘,有興趣的同學(xué)可以看一下官方的建議,https://medium.com/androiddevelopers/viewmodels-and-livedata-patterns-antipatterns-21efaef74a54辙纬,作者提出了更多的使用建議豁遭,相信看完以后,你會(huì)對(duì)LiveData有更深的認(rèn)識(shí)贺拣。中文翻譯在https://zhuanlan.zhihu.com/p/33206893蓖谢。
??Chow Chow &C U Next Time