ViewModel 是google推出的架構(gòu)組件之一蜜葱,它被設(shè)計用于存儲和管理UI相關(guān)的數(shù)據(jù)侠姑。
背景:
1方便數(shù)據(jù)存儲
以生命周期的方式存儲和管理UI相關(guān)數(shù)據(jù)助析。當屏幕旋轉(zhuǎn)等改變時妄痪,數(shù)據(jù)能夠被恢復(fù)。
2生命周期控制
使用fragment時我們都會對它復(fù)雜的生命周期處理感到痛苦卓起,稍有不慎報各種null異常。ViewModel凹炸,Lifecycle等組件的推出戏阅,可以有效的解決生命周期的處理問題,提高app的穩(wěn)定性啤它。`
3 DataBinding數(shù)據(jù)驅(qū)動UI
從字面意思看ViewModel就是activity fragment的數(shù)據(jù)抽象模型奕筐。我們知道activity fragment是由系統(tǒng)管理,不受app控制蚕键,當內(nèi)存不足時救欧,系統(tǒng)隨時都有可能回收殺死app。所以這也是android app開發(fā)具有挑戰(zhàn)的地方锣光,我們需要在不確定的環(huán)境下保證我們的業(yè)務(wù)流程順利進行笆怠。由于ViewModel設(shè)計是和activity fragment的生命周期是解耦的,所以當activity fragmegnt重新create時誊爹,如果ViewModel已經(jīng)創(chuàng)建過蹬刷,則仍使用原ViewModel。
ViewMode生命周期見下圖:
如何使用:
1自定義ViewModel
class UserModel extends ViewModel{
String name;
String age;
}
2 獲取ViewModel
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
UserModel model = ViewModelProviders.of(this).get(UserModel.class);
}
}
因為ViewModel生命周期感知的频丘,所以我們不需要手動釋放办成,使用起來非常方便。
注意事項:
ViewModel不可以持有activity fragment等view的引用搂漠,否則會導(dǎo)致內(nèi)存泄漏迂卢。
讀到這里你可能會有如下疑問:
ViewModel 為什么不可以持有activity fragment等View的引用
ViewModel 如果感知activity fragment的生命周期
ViewModel 如何保存數(shù)據(jù)
接下來我們根據(jù)上述疑問,跟蹤ViewModel 的相關(guān)代碼具體分析桐汤。
以ViewModelProviders.of(this).get(UserModel.class); 這行代碼作為切入點
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
FragmentActivity activity = fragment.getActivity();
if (activity == null) {
throw new IllegalArgumentException(
"Can't create ViewModelProvider for detached fragment");
}
initializeFactoryIfNeeded(activity.getApplication());
return new ViewModelProvider(ViewModelStores.of(fragment), sDefaultFactory);
}
1 創(chuàng)建默認的工廠方法而克,實例化新的ViewModels
2 通過傳入fragment或者acitity參數(shù),new ViewModelProvider實例并返回怔毛。
這里有2個關(guān)鍵的代碼點
1 ViewModelStores.of(fragment)
2 return new ViewModelProvider(…)
針對代碼點1 ViewModelStores.of(fragment) 查看ViewModelStores源碼
@MainThread
public static ViewModelStore of(FragmentActivity activity) {
return holderFragmentFor(activity).getViewModelStore();
}
它通過holderFragmentFor函數(shù)返回ViewModelStore對象
繼續(xù)跟蹤holderFragmentFor函數(shù)员萍,找到HolerFragment 這個關(guān)鍵類
從HolerFragment類的代碼中我們找到了ViewModel感知fragment,activity生命周期的原因拣度。
Google在底層默默的create了一個新的HolderFragment 對象碎绎,
由HolderFragment負責(zé)生命周期感知螃壤,當onDestroy()時清理ViewModelStore
持有ViewModelStore對象,setRetainInstance(true) 保證當界面旋轉(zhuǎn)被銷毀再重建時保證mViewModelStore 不被銷毀筋帖。但對于因內(nèi)存被系統(tǒng)殺死后重新進入奸晴,數(shù)據(jù)不會被恢復(fù)。
public class HolderFragment extends Fragment {
private ViewModelStore mViewModelStore = new ViewModelStore();
public HolderFragment() {
setRetainInstance(true);
}
HolderFragment holderFragmentFor(Fragment parentFragment) {
FragmentManager fm = parentFragment.getChildFragmentManager();
HolderFragment holder = findHolderFragment(fm);
......
holder = createHolderFragment(fm);
mNotCommittedFragmentHolders.put(parentFragment, holder);
return holder;
}
}
解決了ViewModel如果感知生命周期的問題幕随,我們再分析下ViewModel的數(shù)據(jù)存儲蚁滋。
我們查看ViewModelStore這個類,發(fā)現(xiàn)ViewModel是被存儲在一個HashMap內(nèi)赘淮,所以它是保存在app內(nèi)存中辕录,并沒有做持久化處理。
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
......
}
針對代碼點2 return new ViewModelProvider(…)梢卸,我們看下ViewModelProvider走诞。
從代碼中可知ViewModelProvider是對ViewModelStore 和Factory的封裝,當viewModel存著時獲取ViewModel蛤高,如果不存在則調(diào)用工廠方法創(chuàng)建ViewModel蚣旱。
public class ViewModelProvider {
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
public ViewModelProvider(ViewModelStore store, Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
......
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
}
總結(jié):
通過代碼的跟蹤分析我們解決了3大疑問,發(fā)現(xiàn)ViewModel的實現(xiàn)主要依賴于HolderFragment類的實現(xiàn)戴陡。
通過添加新的HolderFragment感知生命周期的變化
通過HolderFragment持有ViewModelStore對象
ViewModel存儲在ViewModelStore的hashmap內(nèi)存中塞绿,不做持久化數(shù)據(jù)存儲,當activity fragment處于后臺因內(nèi)存問題被系統(tǒng)殺死后恤批,重新進入后數(shù)據(jù)不會被恢復(fù)异吻。
Fragment和Activity作為key訪問獲取ViewModel對象
ViewModel不能持有activity,fragment等view的引用喜庞,避免內(nèi)存泄漏
參考
https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html
android source code 8.0