The ViewModel class is designed to store and manage UI-related data so that the data survives configuration changes such as screen rotations.
ViewModel類(lèi)的設(shè)計(jì)是為了存儲(chǔ)和管理Ui相關(guān)的數(shù)據(jù),例如配置文件如屏幕旋轉(zhuǎn)使數(shù)據(jù)保留下來(lái)
應(yīng)用程序組件(如activity或者fragment),是由android的Framework框架管理的生命周期。框架決定銷(xiāo)毀或者創(chuàng)建她們,這是基于一些用戶的行為或者設(shè)備的事件,而這一切都在你的控制范圍外。
因?yàn)橐恍?duì)象可能會(huì)被系統(tǒng)重建或者銷(xiāo)毀,你所保存的任何數(shù)據(jù)都會(huì)丟失。例如:如果你的activity中有一些用戶列表,當(dāng)配置文件更改導(dǎo)致的activity重建,新的activity就必須重新獲取用戶列表,對(duì)于簡(jiǎn)單的數(shù)據(jù),activity可以從onSaveInstanceState()方法或者onCreate()的Bundle中重新獲取數(shù)據(jù),但是這個(gè)方法僅僅適用于小的數(shù)據(jù)例如UI狀態(tài),不能是大量的數(shù)據(jù),例如用戶列表。
另一個(gè)問(wèn)題是,這些Ui控制器(activity或者fragment)經(jīng)常進(jìn)行需要一些時(shí)間的一步操作。Ui控制器需要管理這些回調(diào),并在銷(xiāo)毀的時(shí)候清理它們,避免內(nèi)存泄漏。這需要大量的維護(hù),并且在進(jìn)行更改配置而從新創(chuàng)建對(duì)象的情況下,這是浪費(fèi)資源,因?yàn)樾枰l(fā)出相同的調(diào)用。
將視圖數(shù)據(jù)所有權(quán)與UI控制器邏輯分離是更容易和更有效,Lifecycles提供了一個(gè)名為ViewModel的新類(lèi)。用于UI控制器的輔助類(lèi),負(fù)責(zé)為UI準(zhǔn)備數(shù)據(jù)。在配置更改期間,ViewModel將自動(dòng)保留,以便其保存的數(shù)據(jù)立即可用于下一個(gè)activity或fragment實(shí)例。ViewModel應(yīng)該是獲取和保留用戶列表而不是fragment或activity的責(zé)任。
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
}
}
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
});
}
}
由于ViewModel超出了特定的fragment和activity實(shí)例,所以它不應(yīng)該引用View或任何可能持有對(duì)活動(dòng)上下文的引用的類(lèi)。如果ViewModel需要Application上下文(例如,找到系統(tǒng)服務(wù)),則可以擴(kuò)展AndroidViewModel類(lèi),并在構(gòu)造函數(shù)中接收Application的構(gòu)造函數(shù)(由于Application類(lèi)擴(kuò)展了Context)
可以理解為ViewMode不要持有Context,如果必須使用context就實(shí)現(xiàn)AndroidViewModel.
在Fragment之間共享數(shù)據(jù)
使用ViewModel對(duì)象解決activity中多個(gè)fragment相互通信。其中我們有一個(gè)片段,用戶從列表中選擇一個(gè)項(xiàng)目,另一個(gè)片段顯示所選項(xiàng)目的內(nèi)容。
這些fragment可以使用其activity范圍共享一個(gè)ViewModel來(lái)處理此通信
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 onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends LifecycleFragment {
public void onActivityCreated() {
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// update UI
});
}
}
請(qǐng)注意,在獲取ViewModelProvider時(shí),兩個(gè)fragment都使用getActivity()。這意味著他們都將收到相同的SharedViewModel實(shí)例,該實(shí)例是作用域的活動(dòng)。
這種方法的好處包括:
- activity不需要做任何事情,也不需要知道通信的任何內(nèi)容。
- 除了SharedViewModel之外,fragment不需要彼此了解。如果其中一個(gè)消失,另一個(gè)會(huì)照常工作
- 每個(gè)片段都有自己的生命周期,不受其他片段的生命周期的影響。實(shí)際上,在一個(gè)片段替換另一個(gè)片段的UI中,UI工作沒(méi)有任何問(wèn)題