轉(zhuǎn)載請(qǐng)標(biāo)明出處http://www.reibang.com/p/7fe5c2f9459a
前言:在上一篇http://www.reibang.com/p/fb8d33168f57中說(shuō)到要把MVVM的坑補(bǔ)上挫以。哪有跳過(guò)MVVM學(xué)DataBinding就算的道理顾瞪。
但是由于日常工作任務(wù)以及個(gè)人的緣故膏执,拖了半個(gè)月。經(jīng)過(guò)一段時(shí)間的學(xué)習(xí)枕稀,才發(fā)現(xiàn)DataBinding是構(gòu)建MVVM的工具。
很早以前就使用的MVC過(guò)于耦合,Activity十分臃腫近忙。MVP模式雖然解決了MVC耦合的問(wèn)題,但是對(duì)象持有的內(nèi)存泄露智润,和V層一定程度耦合及舍,以及P層接口過(guò)多代碼臃腫。都是潛在的問(wèn)題窟绷,日常開(kāi)發(fā)中經(jīng)尘饴辏可見(jiàn)。相較之下兼蜈,學(xué)習(xí)了MVVM就一個(gè)感覺(jué)攘残,真香。
1.MVVM是什么
MVVM是Model-View-ViewModel的簡(jiǎn)寫(xiě)为狸。最早是Web開(kāi)發(fā)的概念歼郭,它本質(zhì)上就是MVC 的改進(jìn)版。MVVM 就是將其中的View 的狀態(tài)和行為抽象化钥平,讓我們將視圖 UI 和業(yè)務(wù)邏輯分開(kāi)实撒。由ViewModel進(jìn)行數(shù)據(jù)邏輯的處理,View專注視圖UI。Model和傳統(tǒng)意義的model有些許不同,這里不止是指實(shí)體對(duì)象倒得,還包括了數(shù)據(jù)的獲取,存儲(chǔ)负敏。MVVM是由數(shù)據(jù)驅(qū)動(dòng)UI的,且ViewModel可復(fù)用秘蛇,View和ViewModel之間十分解耦其做,可以在日常工作中分開(kāi)編寫(xiě)。
2.MVVM的使用
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:24.2.0'
implementation "android.arch.lifecycle:extensions:1.1.0"
}
這里會(huì)用到lifecycle組件赁还,lifecycle是Google提供的應(yīng)用組件生命周期管理組件妖泄。簡(jiǎn)單來(lái)說(shuō),它可以很好的對(duì)activity艘策,F(xiàn)ragment等的生命周期進(jìn)行監(jiān)控管理蹈胡,從而很好的避免內(nèi)存泄漏甚至崩潰。官方文檔中也有描述。
3.MVVM中的框架搭建
3.1ViewModel
官方提供了ViewModel類(lèi)供我們繼承罚渐。viewmodel是貫穿于整個(gè)activity生命周期的却汉,只有activity銷(xiāo)毀之后,viewmodel生命周期才結(jié)束荷并。ViewModel只關(guān)注數(shù)據(jù)業(yè)務(wù)邏輯合砂,ViewModel中不做視圖相關(guān)的操作,更不持有控件引用源织。通常會(huì)搭配LiveData來(lái)使用翩伪,下面會(huì)提及。
public class UserViewModel extends ViewModel {
}
如果你在viewmodel中需要用到上下文雀鹃,可以繼承AndroidViewModel幻工。
public class UserViewModel extends AndroidViewModel {
public UserViewModel(@NonNull Application application) {
super(application);
}
}
通常,是使用DataBinding的ObservableFields(實(shí)現(xiàn)了BaseObservable)實(shí)現(xiàn)對(duì)象可觀察的黎茎。
public class UserViewModel extends AndroidViewModel {
ObservableField<User> liveDataUser = new ObservableField<>();
}
但是更多的我們會(huì)使用LiveData,LiveData能實(shí)現(xiàn)對(duì)象觀察当悔,還可以感知組件生命周期傅瞻,ObservableFields則需要自己根據(jù)DataBinding手動(dòng)處理生命周期問(wèn)題。且LiveData可以主動(dòng)調(diào)用postValue盲憎,setValue通知UI嗅骄,且LiveData可以更好的許多架構(gòu)組件 (如Room、WorkManager) 相互配合使用饼疙。這個(gè)在Google Android開(kāi)發(fā)者官方賬號(hào)也有提到溺森。我們?cè)趘iewmodel中使用LiveData,然后在view中配合LiveData的observe方法窑眯,即可觀察數(shù)據(jù)變化屏积。
public class UserViewModel extends AndroidViewModel {
MutableLiveData<User> liveDataUser = new MutableLiveData<>();
public UserViewModel(@NonNull Application application) {
super(application);
}
public LiveData<User> Login() {
//vm傾向于對(duì)數(shù)據(jù)的處理,而不是對(duì)于view的處理
UserBiz userBiz = new UserBiz();
//例如數(shù)據(jù)層網(wǎng)絡(luò)請(qǐng)求操作
userBiz.Login("基佬2", new ILoginListener() {
@Override
public void onSuccess(User user) {
liveDataUser.postValue(user);
}
@Override
public void onFail() {
}
});
return liveDataUser;
}
}
3.2View
這里activity就是我們真正意義上的View,并且View并不在意數(shù)據(jù)業(yè)務(wù)邏輯磅甩,不操作不處理數(shù)據(jù)炊林,他只在乎UI該做的事情。
public class MainActivity extends AppCompatActivity {
private UserViewModel mNameViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// mNameViewModel.getUsers().observe(this, new Observer<List<User>>() {
// @Override
// public void onChanged(List<User> users) {
// }
// });
mNameViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
mNameViewModel.Login().observe(this, (User users) -> {
//我們更傾向于讓activity專注于視圖的處理卷要,而不是對(duì)于數(shù)據(jù)的處理渣聚。
//訂閱LiveData中User列表數(shù)據(jù)變化,以lambda形式定義Observer,進(jìn)行監(jiān)聽(tīng)
Toast.makeText(this, "加載成功:"+users.toString(), Toast.LENGTH_SHORT).show();
});
}
}
像這樣僧叉,View就可以通過(guò)ViewModelProviders找到你的ViewModel奕枝,調(diào)用方法且通過(guò)上文提到的LiveData監(jiān)聽(tīng)訂閱。在View里只做View的事情瓶堕,不涉及數(shù)據(jù)隘道。
3.3Model
這里Model不單是實(shí)體模型,還包括了網(wǎng)絡(luò)請(qǐng)求,服務(wù)等薄声。是對(duì)數(shù)據(jù)的獲取当船,存儲(chǔ)的操作的。
public class UserBiz implements IUserBiz {
@Override
public void Login(String name, ILoginListener loginListener) {
User user = new User();
//模擬網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
user.setName(name);
user.setAge("18歲2");
user.setGender("男2");
loginListener.onSuccess(user);
}
}).start();
}
}
最終就可以實(shí)現(xiàn)5S后彈出toast的效果默辨。甚至德频,如果你想達(dá)到databinding的單向綁定,只需要findViewById配合控件set即可缩幸。很簡(jiǎn)單的一個(gè)數(shù)據(jù)變化壹置,UI變化的過(guò)程。
而且就算是想到達(dá)到雙向綁定的效果表谊,通過(guò)findViewById找到控件對(duì)控件進(jìn)行監(jiān)聽(tīng)钞护,當(dāng)控件內(nèi)容變化的時(shí)候使用LiveData進(jìn)行setValue或者postValue,也能達(dá)到爆办。
4.思考
學(xué)到這可以發(fā)現(xiàn)在MVVM难咕,是離不開(kāi)LiveData對(duì)于數(shù)據(jù)的訂閱的。但是對(duì)比前面學(xué)習(xí)的DataBinding距辆,兩者都可以實(shí)現(xiàn)雙向綁定余佃,而且網(wǎng)上很多文章都是將兩者共同使用的,所以我很想弄明白他們之前到底有什么優(yōu)劣跨算,所以才有下面的結(jié)論爆土。
4.1雙向綁定
使用viewmodel也可以通過(guò)livedata在數(shù)據(jù)訂閱回調(diào)中實(shí)現(xiàn)視圖的變化,數(shù)據(jù)更新視圖更新诸蚕。
但需要編寫(xiě)findViewById和set的過(guò)程步势,模塊一多代碼非常繁重,activity依然臃腫背犯。
使用viewmodel也可以通過(guò)livedata也可以通過(guò)setValue方法實(shí)現(xiàn)視圖更新引起數(shù)據(jù)更新坏瘩。
但一樣需要編寫(xiě)findViewById和控件監(jiān)聽(tīng)事件的過(guò)程,而且這樣會(huì)導(dǎo)致view需要去操作數(shù)據(jù)媳板。不符合MVVM的理念桑腮。
相較之下DataBinding實(shí)現(xiàn)非常簡(jiǎn)單,很多代碼都是自動(dòng)生成了在ActivityBindingImpl中蛉幸,代碼簡(jiǎn)潔破讨。
但DataBinding出現(xiàn)報(bào)錯(cuò)不容易定位和處理,對(duì)于新手而言不大友好奕纫。
4.2生命周期
DataBinding一樣可以使用ObservableField實(shí)現(xiàn)數(shù)據(jù)觀察提陶,但LiveData在數(shù)據(jù)對(duì)于組件生命周期的表現(xiàn)更加優(yōu)秀,且兼容更多匹层,是官方推薦的隙笆。
5.結(jié)論
MVVM模式的優(yōu)勢(shì)不言而喻锌蓄,而且由官方直接提供庫(kù),學(xué)了之后真的逃不過(guò)真香撑柔,組件的生命周期被監(jiān)聽(tīng)瘸爽,最大限度的避免內(nèi)存溢出甚至閃退。目前還感受不到MVVM在Android上的表現(xiàn)相較于傳統(tǒng)框架的大缺點(diǎn)铅忿〖艟觯可能比較弱勢(shì)的地方就是出現(xiàn)Bug的時(shí)候比較難定位,你無(wú)法得知出現(xiàn)問(wèn)題的是View層還是Model層檀训。
作者:陌過(guò)生人丶
鏈接:http://www.reibang.com/p/7fe5c2f9459a
來(lái)源:簡(jiǎn)書(shū)
著作權(quán)歸作者所有柑潦。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處峻凫。