ViewModel設(shè)計(jì)的目的就是存放和處理和UI相關(guān)的數(shù)據(jù)柏肪,并且這些數(shù)據(jù)不受配置變化(Configuration Changes姐刁,例如:旋轉(zhuǎn)屏幕,組件被系統(tǒng)回收)的影響烦味。
由于(Activity/Fragment)會(huì)被系統(tǒng)隨時(shí)銷毀或重新創(chuàng)建聂使,因此,任何存放在這里的數(shù)據(jù)都可能會(huì)丟失谬俄。例如柏靶,Activity中有一個(gè)查詢得到的用戶列表,當(dāng)Activity被重新創(chuàng)建時(shí)溃论,新的Activity需要再次去獲取用戶數(shù)據(jù)宿礁。對(duì)于簡(jiǎn)單的數(shù)據(jù)可以使用 onSaveInstanceState()
保存,在onCreate()
中恢復(fù)蔬芥。對(duì)于少量的用戶數(shù)據(jù),比如UI狀態(tài)是沒(méi)有問(wèn)題的控汉。但是對(duì)于大量的數(shù)據(jù)笔诵,比如用戶列表,這用做就會(huì)不合適(not suitable)姑子。
另一個(gè)問(wèn)題是乎婿,UI組件會(huì)頻繁的調(diào)用異步回調(diào),這些回調(diào)可能會(huì)非常耗時(shí)街佑。這就需要UI組件管理這些調(diào)用谢翎,并且在UI組件銷毀時(shí)清除這些調(diào)用。這會(huì)花費(fèi)很多的維護(hù)成本,而且當(dāng)UI由于configuration change
重新創(chuàng)建時(shí)沐旨,又需要重新調(diào)用森逮,這明顯是一種資源浪費(fèi)(比如網(wǎng)絡(luò)請(qǐng)求)。
最后磁携,還有一個(gè)問(wèn)題就是UI組件需要對(duì)用戶的操作作出響應(yīng)褒侧,并且處理和操作系統(tǒng)的通信。這樣把代碼放在UI組件中會(huì)使這部分代碼變得臃腫,而且對(duì)測(cè)試也不太友好闷供。
ViewModel就是用于解決上述問(wèn)題的烟央。ViewModel用于為UI組件提供數(shù)據(jù),并且能夠在旋轉(zhuǎn)屏幕等Configuration Change發(fā)生時(shí)歪脏,仍能保持里面的數(shù)據(jù)疑俭。當(dāng)UI組件恢復(fù)時(shí),可以立刻向UI提供數(shù)據(jù)婿失。一起看下代碼:
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<Users>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// do async operation to fetch users
}
}
Activity訪問(wèn)User List數(shù)據(jù):
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
那么問(wèn)題來(lái)了钞艇,假如用戶按返回鍵,主動(dòng)銷毀了這個(gè)Activity呢移怯?這時(shí)系統(tǒng)會(huì)調(diào)用ViewModel的onCleared()
方法香璃,清除ViewModel中的數(shù)據(jù)。
在Fragments間分享數(shù)據(jù)
有時(shí)候一個(gè)Activity中的兩個(gè)或多個(gè)Fragment需要分享數(shù)據(jù)或者相互通信舟误,這樣就會(huì)帶來(lái)很多問(wèn)題葡秒,比如數(shù)據(jù)獲取,相互確定生命周期嵌溢。
使用ViewModel可以很好的解決這個(gè)問(wèn)題眯牧。假設(shè)有這樣兩個(gè)Fragment,一個(gè)Fragment提供一個(gè)列表赖草,另一個(gè)Fragment提供點(diǎn)擊每個(gè)item現(xiàn)實(shí)的詳細(xì)信息学少。
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends LifecycleFragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// update UI
});
}
}
兩個(gè)Fragment都是通過(guò)getActivity()
來(lái)獲取ViewModelProvider。這意味著兩個(gè)Activity都是獲取的屬于同一個(gè)Activity的同一個(gè)ShareViewModel
實(shí)例秧骑。
這樣做優(yōu)點(diǎn)如下:
- Activity不需要寫任何額外的代碼版确,也不需要關(guān)心Fragment之間的通信。
- Fragment不需要處理除
SharedViewModel
以外其他的代碼乎折。這兩個(gè)Fragment不需要知道對(duì)方是否存在绒疗。 - Fragment的生命周期不會(huì)相互影響
ViewModel的生命周期
ViewModel只有在Activity finish或者Fragment detach之后才會(huì)銷毀。下面這張圖顯示了詳細(xì)的生命周期:
ViewModel和SavedInstanceState對(duì)比
ViewModel使得在configuration change(旋轉(zhuǎn)屏幕等)保存數(shù)據(jù)變的十分方便骂澄,但是這不能用于應(yīng)用被系統(tǒng)殺死時(shí)持久化數(shù)據(jù)吓蘑。舉個(gè)簡(jiǎn)單的例子,有一個(gè)界面展示國(guó)家信息坟冲。不應(yīng)該把整個(gè)國(guó)家信息放到SavedInstanceState里磨镶,而是把國(guó)家對(duì)應(yīng)的id放到SavedInstanceState,等到界面恢復(fù)時(shí)健提,再通過(guò)id去獲取詳細(xì)的信息琳猫。這些詳細(xì)的信息應(yīng)該被存放在數(shù)據(jù)庫(kù)中。說(shuō)到數(shù)據(jù)庫(kù)私痹,下篇文章將會(huì)介紹Android Architecture Components提供的Room來(lái)操作數(shù)據(jù)庫(kù)沸移。
相關(guān)文章:
理解Android Architecture Components系列(一)
理解Android Architecture Components系列(二)
理解Android Architecture Components系列之Lifecycle(三)
理解Android Architecture Components系列之LiveData(四)
理解Android Architecture Components系列之ViewModel(五)
理解Android Architecture Components系列之Room(六)
理解Android Architecture Components系列之Paging Library(七)
理解Android Architecture Components系列之WorkManager(八)