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

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