剖析 Android 架構元件之 ViewModel
iewModel 是 Android 架構元件之一,用於分離 UI 邏輯與 UI 資料。在發生 Configuration Changes 時,它不會被銷燬。在介面重建後,方便開發者呈現介面銷燬前的 UI 狀態。
本文主要分析 ViewModel 的以下3個方面:
獲取和建立過程。
Configuration Changes 存活原理。
銷燬過程。
1. 依賴庫
implementation "androidx.fragment:fragment:1.0.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:2.0.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
2. 主要類與介面
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProvider.Factory;
import androidx.lifecycle.ViewModelProviders;
import androidx.lifecycle.ViewModelStore;
import androidx.lifecycle.ViewModelStoreOwner;
3. ViewModel
ViewModel 是一個抽象類,類中只定義了一個空實現的 onCleared() 方法。
@SuppressWarnings() { } }
3.1 AndroidViewModel
AndroidViewModel 類擴充套件了 ViewModel 類,增加了 Application 欄位,在構造方法初始化,並提供了 getApplication() 方法。
public class AndroidViewModel extends ViewModel {
private Application mApplication;
public AndroidViewModel(@NonNull Application application) {
mApplication = application;
}
/**
* Return the application.
*/
@NonNull
public
4. 獲取和建立過程分析
獲取 ViewModel 物件程式碼如下:
ViewModelProviders.of(activityOrFragment).get(ViewModel::class.java)
4.1 ViewModelProviders
ViewModelProviders 類提供了4個靜態工廠方法 of() 建立新的 ViewModelProvider 物件。
ViewModelProviders.of(Fragment)
ViewModelProviders.of(FragmentActivity)
ViewModelProviders.of(Fragment, Factory)
ViewModelProviders.of(FragmentActivity, Factory)
4.2 ViewModelProvider
ViewModelProvider 負責提供 ViewModel 物件,類中定義了以下兩個欄位:
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
先說說這兩個類的功能。
4.3 ViewModelProvider.Factory
Factory 介面定義了一個建立 ViewModel 的介面 create(),ViewModelProvider 在需要時呼叫該方法新建 ViewModel 物件。
public interface Factory {
Android 已經內建了2個 Factory 實現類,分別是:
AndroidViewModelFactory 實現類,可以建立 ViewModel 和 AndroidViewModel 子類物件。
NewInstanceFactory 類,只可以建立 ViewModel 子類物件。
它們的實現都是透過反射機制呼叫 ViewModel 子類的構造方法建立物件。
public static class NewInstanceFactory implements Factory {
@Override
public
AndroidViewModelFactory 繼承 NewInstanceFactory 類,是個單例,支援建立 AndroidViewModel 子類物件。
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static AndroidViewModelFactory sInstance;
public static AndroidViewModelFactory getInstance(Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
public AndroidViewModelFactory(Application application) {
mApplication = application;
}
@Override
public
4.4 ViewModelStore
ViewModelStore 類中維護一個 Map
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
}
final ViewModel get(String key) {
return mMap.get(key);
}
}
4.5 ViewModelStoreOwner
ViewModelStore 是來自於 FragmentActivity 和 Fragment,它們實現了 ViewModelStoreOwner 介面,返回當前 UI 作用域裡的 ViewModelStore 物件。
public interface ViewModelStoreOwner {
ViewModelStore getViewModelStore();
}
在 Fragment 類中的實現如下:
public ViewModelStore getViewModelStore() {
if (getContext() == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}
在 FragmentActivity 類中的實現如下:
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}
4.6 建立 ViewModelProvider
回到 of() 方法的實現
public static ViewModelProvider of(FragmentActivity activity, Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
在建立 ViewModelProvider 物件時需要傳入 ViewModelStore 和 Factory 物件。若 factory 為 null,將使用 AndroidViewModelFactory 單例物件。
4.7 獲取 ViewModel 物件
呼叫 ViewModelProvider 物件的 get() 方法獲取 ViewModel 物件,如果在 ViewModelStore 裡不存在,則使用 Factory 建立一個新的物件並存放到 ViewModelStore 裡。
public <T extends ViewModel> T get(String key, Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
5. Configuration Changes 存活原理
當 Activity 或 Fragment 被系統重建時,ViewModel 物件不會被銷燬,新的 Activity 或 Fragment 物件拿到的是同一個 ViewModel 物件。
在 FragmentActivity#onRetainNonConfigurationInstance() 方法中,會將 ViewModelStore 物件保留起來。
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
if (fragments == null && mViewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = mViewModelStore;
nci.fragments = fragments;
return nci;
}
然後在 onCreate() 方法能獲取之前保留起來的 ViewModelStore 物件。
protected void onCreate(Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
// ...
}
那 Fragment 作用域裡是如何實現的呢?在 FragmentActivity 的 onRetainNonConfigurationInstance() 方法中裡有這樣一句程式碼:
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
實現保留的機制是一樣的,只不過放在 FragmentManagerNonConfig 物件中。是在 FragmentManager#saveNonConfig() 方法中將 ViewModelStore 物件儲存到 FragmentManagerNonConfig 裡的。
void saveNonConfig() {
ArrayList
該方法的呼叫順序是:FragmentActivity#onSaveInstanceState() -> FragmentManager#saveAllState() -> FragmentManager#saveNonConfig()。
6. 銷燬過程
在 FragmentActivity 類的 onDestory() 方法中。
@Override
protected void onDestroy() {
super.onDestroy();
if (mViewModelStore != null && !isChangingConfigurations()) {
mViewModelStore.clear();
}
mFragments.dispatchDestroy();
}
在 Fragment 類的 onDestory() 方法中。
public void onDestroy() {
mCalled = true;
FragmentActivity activity = getActivity();
boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations();
if (mViewModelStore != null && !isChangingConfigurations) {
mViewModelStore.clear();
}
}
先判斷是否有發生 Configuration Changes,如果沒有則會呼叫 ViewModelStore 的 clear() 方法,再一一呼叫每一個 ViewModel 的 onCleared() 方法。
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
7. 總結
以上便是 ViewModel 3個主要過程的剖析,這裡做一下總結。
透過 ViewModelProviders 建立 ViewModelProvider 物件,呼叫該物件的 get() 方法獲取 ViewModel 物件。
當 ViewModelStore 裡不存在想要的物件,ViewModelProvider 會使用 Factory 新建一個物件並存放到 ViewModelStore 裡。
當發生Configuration Changes 時,FragmentActivity 利用 getLastNonConfigurationInstance()、onRetainNonConfigurationInstance() 方法實現 ViewModelStore 的保留與恢復,進而實現 ViewModel 物件的保活。
當 FragmentActivity 和 Fragment 被銷燬時,會根據是否發生 Configuration Changes 來決定是否銷燬 ViewModel。
作者:吳下阿吉
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69900364/viewspace-2284207/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 初學 Android 架構元件之 ViewModelAndroid架構元件View
- Android 架構元件 - Lifycycle, LiveData, ViewModelAndroid架構元件LiveDataView
- Android 官方架構元件(三)——ViewModelAndroid架構元件View
- Android官方架構元件之LiveData + ViewModel + Room 原始碼分析一Android架構元件LiveDataViewOOM原始碼
- Android官方架構元件ViewModel:從前世今生到追本溯源Android架構元件View
- Android架構元件:用ViewModelCommandLiveData處理ViewModel中的事件釋出Android架構元件ViewLiveData事件
- Android 官方架構元件之 LifecycleAndroid架構元件
- Android Jetpack 架構元件之 NavigationAndroidJetpack架構元件Navigation
- 初學 Android 架構元件之 LifecycleAndroid架構元件
- Android Jetpack架構元件(七)之WorkManagerAndroidJetpack架構元件
- 【AAC 系列四】深入理解架構元件:ViewModel架構元件View
- Jetpack架構元件學習(2)——ViewModel和Livedata使用Jetpack架構元件ViewLiveData
- Android Jetpack之ViewModelAndroidJetpackView
- Android Jetpack 之 ViewModelAndroidJetpackView
- Android新元件架構——LifecylceAndroid元件架構
- Android 元件化架構概要Android元件化架構
- Android Jetpack Architecture原理之ViewModelAndroidJetpackView
- Android MVVM元件化架構方案AndroidMVVM元件化架構
- Android架構元件-DataBinding的使用Android架構元件
- Android架構元件WorkManager詳解Android架構元件
- 《Android元件化架構》上市了Android元件化架構
- Android 官方架構元件(一)——LifecycleAndroid架構元件
- Android 官方架構元件(二)——LiveDataAndroid架構元件LiveData
- Android Jetpack元件 - ViewModel,LiveData使用以及原理AndroidJetpack元件ViewLiveData
- [Android元件化]AAB外掛化架構Android元件化架構
- Android 架構元件的最新進展 (上篇)Android架構元件
- Unity應用架構設計(5)——ViewModel之間如何共享資料Unity應用架構View
- Unity應用架構設計 ViewModel之間實現共享資料Unity應用架構View
- Android官方架構元件Lifecycle:生命週期元件詳解&原理分析Android架構元件
- Android 控制元件架構與自定義控制元件詳解Android控制元件架構
- Android 架構設計:MVC、MVP、MVVM和元件化Android架構MVCMVPMVVM元件化
- Android官方架構元件Navigation:大巧不工的Fragment管理框架Android架構元件NavigationFragment框架
- React Native新架構剖析React Native架構
- 專案實戰之元件化架構元件化架構
- Android 架構之長連線技術Android架構
- Android-ViewModel 使用指北AndroidView
- Android ViewModel 引入協程AndroidView
- Android 架構元件 - 讓天下沒有難做的 AppAndroid架構元件APP