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í)就是對ViewModelProvider
的包裝類。
正是因?yàn)橥ㄟ^ViewModelProvider
創(chuàng)建ViewModel的方式骆捧,ViewModel才具備了一些比較方便實(shí)用的功能澎羞。
生命周期
因?yàn)閯?chuàng)建ViewModel時(shí)傳入了activity/fragment對象實(shí)例(ViewModelProviders.of(this)
),所以ViewModel可以感知宿主的生命周期敛苇。
當(dāng)宿主onDestroy()
時(shí)候ViewModel便會自行銷毀掉妆绞,除此之前,當(dāng)屏幕旋轉(zhuǎn)的時(shí)候枫攀,Activity會被recreate括饶,Activity會經(jīng)過幾個(gè)生命周期方法,但是這個(gè)時(shí)候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是同一個(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ù)請求
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ù)的變化即可牺弹。
注意事項(xiàng)
ViewModel看似使用簡單浦马,但是在實(shí)際使用中會有一些點(diǎn)需要關(guān)注的。
1. 數(shù)據(jù)源的初始化
ViewModel本質(zhì)上就是管理各種LiveData數(shù)據(jù)源的张漂,但一定要注意的是在外界getData()
前一定要初始化數(shù)據(jù)源晶默,因?yàn)橥饨绔@得數(shù)據(jù)源后一般會直接注冊觀察者,如果這時(shí)候數(shù)據(jù)源沒有初始化就會空指針異常航攒。
2. 數(shù)據(jù)源的更新
上面的例子中loadData()
方法更新數(shù)據(jù)源是直接用當(dāng)前data對象更新的磺陡,但是在實(shí)際使用中每次請求數(shù)據(jù)后極有可能會發(fā)生數(shù)據(jù)請求模塊返回一個(gè)新的LiveData實(shí)例,這種情況不能直接將當(dāng)前的data重新賦值:
data = newData;
這樣寫的話外界設(shè)置的觀察者就會失效了漠畜。