前言
前幾篇文章介紹了Jetpack及其LiveData冰肴,越發(fā)的發(fā)現(xiàn)Jetpack在Android開發(fā)中地位勢不可擋茶袒,在Android developers官網(wǎng)已經(jīng)將Jetpack放在頂部一級列表餐抢,不學(xué)習(xí)點Jetpack怎么好意思是做Android開發(fā)的。
Jetpack分四類玲献,基礎(chǔ)廓啊、架構(gòu)、行為乾胶、界面抖剿,今天學(xué)習(xí)的架構(gòu)的中的 ViewModel,他和LiveData配合使用可以吊炸天识窿。還不懂LiveData的同仁斩郎,請看先看Jetpack -- LiveData。
一. ViewModel概述
ViewModel是Lifecycle中的一個組件喻频,旨在以注重生命周期的方式存儲和管理界面相關(guān)的數(shù)據(jù)缩宜。讓界面數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)后繼續(xù)存在。Android中的控制器(activity和fragment)銷毀或者重建會丟失數(shù)據(jù)甥温,現(xiàn)在把數(shù)據(jù)存儲在ViewModel锻煌,不會受到控制器的銷毀或者重建而丟失數(shù)據(jù)。
二.ViewModel能解決什么問題
-
解決數(shù)據(jù)丟失問題
上圖是官網(wǎng)給出的姻蚓,展示了屏幕旋轉(zhuǎn)activity的生命周期宋梧,但是ViewModel一直存在,直到activity銷毀才調(diào)用了清除方法onCleared()捂龄。
顯然,viewModel是最好保存數(shù)據(jù)的方式加叁。在沒有ViewModel之前,遇到屏幕切換保存數(shù)據(jù)使用onSaveInstanceState殉农,但是onSaveInstanceState只能保存輕量級數(shù)據(jù)刀脏,大點的數(shù)據(jù)是無法保存的超凳。ViewModel解決了我們這個痛點愈污。 fragment之間數(shù)據(jù)共享
Activity 中的兩個或更多 Fragment 需要相互通信是一種很常見的情況。在以前我們是通過接口回調(diào)實現(xiàn)fragment之間通信轮傍,統(tǒng)一在activity中管理暂雹。有一種情況,一個fragment包含了另一個fragment创夜,也就是一個fragment持有了另一個fragment的引用杭跪。這樣最后的結(jié)果,耦合度太高涧尿,還需要大量的工作系奉,官方給出了代碼示例:
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 Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}
這么寫的好處是:
①Activity 不需要做任何事姑廉,甚至不知道這次交互缺亮,完美解耦。
②Fragment 僅僅與ViewModel交互桥言,不需要知道其他Fragment 的狀態(tài)甚至是否存在萌踱,更不需要持有其引用。所有當(dāng)對方 Fragment 銷毀時号阿,不影響本身任何工作并鸵。
③Fragment 生命周期互不影響,甚至 fragment 替換成其他的 也不影響這個系統(tǒng)的運作扔涧。
解決異步回調(diào)等待結(jié)果問題
App中有好多網(wǎng)絡(luò)請求的工作,這個工作都是耗時的的枯夜,而且一般都是放在控制器(如activity或者fragment)處理,所以必須放在子線程做異步操作卤档,否則會引起ANR。有時候還有控制器已經(jīng)銷毀后才會獲取到網(wǎng)絡(luò)數(shù)據(jù)劝枣,這樣導(dǎo)致內(nèi)存泄漏甚至OOM。如果使用ViewModel就會完美解決此痛點织鲸。減輕UI層負(fù)擔(dān)
控制器(如activity或者fragment)作用是用來展示數(shù)據(jù)、響應(yīng)用戶行為搂擦、處理事件的稳诚。而平時我們會把網(wǎng)絡(luò)或數(shù)據(jù)庫數(shù)據(jù)交給他們瀑踢,會讓其顯得臃腫切難以管理扳还。
從MVC 到MVP橱夭、MVVM氨距,目的是 明確職責(zé),分離控制器負(fù)擔(dān)俏让。我們現(xiàn)在可以把數(shù)據(jù)操作的工作交給 ViewModel。
三.ViewModel具體實現(xiàn)
先看簡單的效果,點踩減一寡喝,點贊加一。
- 自定義Viewmodel繼承ViewModel预鬓,管理一個整型數(shù)據(jù)
/**
* 只管理一個變量number
*/
public class AnflyViewModel extends ViewModel {
public int number = 0;
}
- 在MainActivity獲取ViewModel對象,就可以對數(shù)據(jù)進行操作
//獲取Viewmodel實例
anflyViewModel = ViewModelProviders.of(this).get(AnflyViewModel.class);
//重新創(chuàng)建activity是不會丟失數(shù)據(jù)(橫豎屏切換)
tv_number.setText(String.valueOf(anflyViewModel.number));
3.點擊踩和贊使用ViewModel操作數(shù)據(jù)撬陵,MainActivity負(fù)責(zé)更新UI
@Override
public void onClick(View v) {
//使用ViewModel操作數(shù)據(jù)
switch (v.getId()) {
case R.id.iv_dislike:
anflyViewModel.number--;
break;
case R.id.iv_like:
anflyViewModel.number++;
break;
}
//MainActivity負(fù)責(zé)更新UI
tv_number.setText(String.valueOf(anflyViewModel.number));
}
四.ViewModel實現(xiàn)原理
后續(xù)文章逐漸退出