ViewModel 是Android 架構(gòu)組件中負(fù)責(zé)管理UI相關(guān)數(shù)據(jù)與邏輯的,它的功能定義與MVP架構(gòu)中的Persenter十分相似,配合其他組件使用增加許多方便開發(fā)的功能。
基本使用
定義一個(gè)ViewModel只需要繼承ViewModel抽象類即可:
public class MainViewModel extends ViewModel {
}
然后我們就可以在activity/fragment中實(shí)例化它:
MainViewModel viewModel = ViewModelProviders.of(this).get(MainViewModel.class);
注意:如果想要正常使用ViewModel的全部功能,不能直接new出ViewModel的實(shí)例,而是使用ViewModelProvider類創(chuàng)建,上面的ViewModelProviders其實(shí)就是對(duì)ViewModelProvider的包裝類。
正是因?yàn)橥ㄟ^ViewModelProvider創(chuàng)建ViewModel的方式,ViewModel才具備了一些比較方便實(shí)用的功能。
生命周期
因?yàn)閯?chuàng)建ViewModel時(shí)傳入了activity/fragment對(duì)象實(shí)例(ViewModelProviders.of(this)),所以ViewModel可以感知宿主的生命周期。

當(dāng)宿主onDestroy()時(shí)候ViewModel便會(huì)自行銷毀掉,除此之前,當(dāng)屏幕旋轉(zhuǎn)的時(shí)候,Activity會(huì)被recreate,Activity會(huì)經(jīng)過幾個(gè)生命周期方法,但是這個(gè)時(shí)候ViewModel還是之前的對(duì)象,并沒有被重新創(chuàng)建。
共享數(shù)據(jù)
public class MainViewModel extends ViewModel{
}
public class Fragment1 extends Fragment{
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainViewModel ViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
}
}
public class Fragment2 extends Fragment{
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainViewModel ViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
}
}
上面的例子中,如果fragment1和fragment2的宿主activity是同一個(gè)的話,那么它們創(chuàng)建的ViewModel是同一個(gè),ViewModel中的數(shù)據(jù)二者可以共享。
更新UI
ViewModel配合LiveData使用可以做到在不持有activity任何引用的情況下更新UI數(shù)據(jù),這是整個(gè)組件架構(gòu)中最有亮點(diǎn)以及最有特色的地方。
public class MainViewModel extends ViewModel{
MutableLiveData<String> data = new MutableLiveData<>();
public LiveData<String> getData(){
return data;
}
public void loadData(){
// 模擬一個(gè)數(shù)據(jù)請(qǐng)求
data.setValue("test");
}
}
public class Fragment1 extends Fragment{
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainViewModel ViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
ViewModel.getData().observe(this,new Observer(){
@Override
public void onChanged(String s){
textView.setText(s);
}
});
}
}
在上面的例子中,textView會(huì)根據(jù)數(shù)據(jù)源的變化更新自己,而ViewModel中不需要考慮UI更新的問題,只需要關(guān)注數(shù)據(jù)的變化即可。
注意事項(xiàng)
ViewModel看似使用簡(jiǎn)單,但是在實(shí)際使用中會(huì)有一些點(diǎn)需要關(guān)注的。
1. 數(shù)據(jù)源的初始化
ViewModel本質(zhì)上就是管理各種LiveData數(shù)據(jù)源的,但一定要注意的是在外界getData()前一定要初始化數(shù)據(jù)源,因?yàn)橥饨绔@得數(shù)據(jù)源后一般會(huì)直接注冊(cè)觀察者,如果這時(shí)候數(shù)據(jù)源沒有初始化就會(huì)空指針異常。
2. 數(shù)據(jù)源的更新
上面的例子中loadData()方法更新數(shù)據(jù)源是直接用當(dāng)前data對(duì)象更新的,但是在實(shí)際使用中每次請(qǐng)求數(shù)據(jù)后極有可能會(huì)發(fā)生數(shù)據(jù)請(qǐng)求模塊返回一個(gè)新的LiveData實(shí)例,這種情況不能直接將當(dāng)前的data重新賦值:
data = newData;
這樣寫的話外界設(shè)置的觀察者就會(huì)失效了。