初到掘金,人生地不熟,喜歡的朋友,點個贊鼓勵下新手唄~
參考文章:
https://developer.android.google.cn/topic/libraries/architecture/viewmodel
https://mp.weixin.qq.com/s/thoXHuXHC3sV90IFttHfXw
https://blog.csdn.net/gaugamela/article/details/56280384
ViewModel
類主要用來儲存和管理與UI
相關的資料,它能夠讓資料在螢幕旋轉等配置資訊改變導致UI
重建的情況下不被銷燬。
ViewModel生命週期
ViewModel
物件存活在系統中不被回收的時間是由建立ViewModel
傳遞給ViewModelProvider
的Lifecycle
決定的。ViewModel
將一直留在記憶體中,直到限定其存在時間範圍的Lifecycle
生命週期結束。對於Activity
,是在Activity destroy時;而對於Fragment
,是在Fragment detach時。
下圖說明了Activity
經歷螢幕旋轉直到最終destroyed掉這整個過程中所經歷的各個生命週期。該圖還在關聯的Activity
生命週期的旁邊顯示了ViewModel
的生命週期。
我們可以看出,ViewModel
的生命週期貫穿Activity
始終,直到Activity
正常結束,並不會因為螢幕旋轉等系統原因而導致ViewModel
生命週期提前結束。同理Fragment
對於ViewModel
也一樣。
本文,我們不討論ViewModel
的使用,而是直接分析它的原理。
ViewModel原理分析
我們分析原始碼的時候要帶著明確目的帶著問題去分析,從小見大,一個一個小問題解決,無頭蒼蠅似的撲進原始碼中,可能事倍功半。
在分析ViewModel
原始碼之前,我們先介紹一下ViewModel
元件中重要的幾個類:
- ViewModel、ViewModelProvider、HolderFragment、ViewModelStore
上面的類圖簡單地描述出了這幾個類的作用以及關係,算是一個小概括,下面,我們直接進入原始碼分析它們具體的實現,以及它們是如何聯絡起來的。
(在這裡預設大家已經知道了ViewModel
的使用)我們知道ViewModel例項的建立是通過 ViewModelProviders.of(this).get(XxxViewModel.class)
生成的,這行程式碼可以分為兩個步驟:
- 第一步:通過
ViewModelProviders.of(this)
生成ViewModelProvider
物件; - 第二步:通過
viewModelProvider.get(XxxViewModel.class)
生成相對ViewModel
物件。
下面我們的原始碼就針對這兩個步驟分析一下ViewModel
架構中重要的幾個類。
ViewModelProvider
ViewModelProvider
是通過ViewModelProviders.of(this)
生成的,我們進入原始碼看看:
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
// 上面的類圖,我們已經說了,生成 ViewModelProvider 例項的時候,如果 factory 傳 null,
// 系統會預設使用 AndroidViewModelFactory 作為 ViewModel 的生產類
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
// 例項化建立一個 ViewModelProvider 物件返回
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}複製程式碼
可以看到,ViewModelProviders.of()
最終會new
一個ViewModelProvider
物件返回。在建立ViewModelProvider
的時候,需要傳入兩個引數,ViewModelStore
以及Factory
。在這裡,我們先不討論ViewModelStores.of(activity)
是如何例項化返回ViewModelStore
物件的,在後面,我們會說到。
先來看一下Factory
類,它的定義很簡單:
public interface Factory {
// 只有一個 create 方法需要重寫,這個方法就返回 ViewModel 物件,
// 我們可以選擇預設使用 AndroidViewModelFactory,也可以自定義 Factory
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}複製程式碼
當我們傳入的factory引數為null的時候,會預設使用AndroidViewModelFactory
:
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static AndroidViewModelFactory sInstance;
// 單例
@NonNull
public static AndroidViewModelFactory getInstance(@NonNull Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
public AndroidViewModelFactory(@NonNull Application application) {
mApplication = application;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
// 當 modelClass 類繼承自 AndroidViewModel
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
// 呼叫 modelClass 類中帶有 Application 引數的構造方法建立一個 ViewMode 返回
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
// 如果 modelClass 類不是繼承自 AndroidViewModel,呼叫 AndroidViewModelFactory 的
// 父類 NewInstanceFactory 的 create 方法生成 ViewModel 物件返回
return super.create(modelClass);
}
}複製程式碼
AndroidViewModelFactory
的父類NewInstanceFactory
也是非常簡單:
public static class NewInstanceFactory implements Factory {
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
// 直接通過反射呼叫 modelClass 類的無參建構函式例項化一個 ViewModel 物件返回
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}複製程式碼
根據上面對Factory
的分析,在傳入的factory引數為null的前提下,我們可以得出以下結論:
- 如果我們自定義的model繼承自
ViewModel
,需要有一個預設無參的構造方法; - 如果我們自定義的model繼承自
AndroidViewModel
,必須要有一個以Application
為唯一引數的建構函式。
當然我們也可以自定義Factory
,在這裡就不討論了,廣大聰明的讀者才是最法力無邊的~
ViewModelStore
上面我們知道了在構造ViewModelProvider
的時候,會通過ViewModelStores.of()
方法獲取到一個ViewModelStore
物件。ViewModelStores
類是用於提供返回ViewModelStore
物件的,下面我們來看看ViewModelStores.of()
究竟做了什麼?
public class ViewModelStores {
private ViewModelStores() {
}
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
// 開發者可以選擇自己讓 Activity 繼承 ViewModelStoreOwner,然後實現 getViewModelStore 方法
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
// holderFragmentFor(activity)方法返回繼承了 ViewModelStoreOwner 的 HolderFragment 例項,
// 呼叫這個 HolderFragment 物件的 getViewModelStore() 即可以拿到 ViewModelStore 例項。
return holderFragmentFor(activity).getViewModelStore();
}
@NonNull
@MainThread
public static ViewModelStore of(@NonNull Fragment fragment) {
// 同理,fragment 也可以繼承 ViewModelStoreOwner ,實現 getViewModelStore 方法
if (fragment instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) fragment).getViewModelStore();
}
// 同上
return holderFragmentFor(fragment).getViewModelStore();
}
}複製程式碼
可以看出,ViewModelStores.of()
方法主要就是從ViewModelStoreOwner
物件中獲取ViewModelStore
物件。至於holderFragmentFor()
方法究竟做了什麼?我們下面在繼續分析,現在,先看看ViewModelStore
:
public class ViewModelStore {
// 用 HashMap 儲存 ViewModel 物件
private final HashMap<String, ViewModel> mMap = new HashMap<>();
// 新添 ViewModel
final void put(String key, ViewModel viewModel) {
// 如果對應 key 的 ViewModel 已經存在,那麼覆蓋它,並且呼叫它的 onCleared 方法
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
// 獲取指定 key 的 ViewModel
final ViewModel get(String key) {
return mMap.get(key);
}
// 呼叫所有 ViewModel 的 onCleared 方法,並且清空整個 HashMap
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}複製程式碼
ViewModelStore
的實現很簡單,主要的作用就是對ViewModel
進行儲存管理,通過一個HashMap
儲存了所有的ViewModel
,分別通過put
方法以及get
方法新增和獲取ViewModel
,通過clear
方法遍歷呼叫所有ViewModel
的onCleared
方法並且清空map。
接下來,我們來看看最核心的一個類,HolderFragment
。
HolderFragment
前面我們分析ViewModelStores.of()
方法的時候,提到過呼叫靜態方法holderFragmentFor()
方法能夠返回一個繼承了ViewModelStoreOwner
的HolderFragment
例項,現在我們就來看看HolderFragment
這個類究竟是何方神聖?為什麼當Activity
由於螢幕旋轉等被系統銷燬時,這個Fragment
例項也不會被銷燬?
public class HolderFragment extends Fragment implements ViewModelStoreOwner {
private static final String LOG_TAG = "ViewModelStores";
// 這是什麼?請看下面註釋分析
private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final String HOLDER_TAG = "android.arch.lifecycle.state.StateProviderHolderFragment";
// 這就是我們存放 ViewModel 的 ViewModelStore,就定義在 HolderFragment裡
private ViewModelStore mViewModelStore = new ViewModelStore();
public HolderFragment() {
// 劃重點啦!!!為什麼當 activity 由於螢幕旋轉等被系統銷燬時,
// 這個 fragment 例項也不會被銷燬?因為設定了 setRetainInstance(true)
setRetainInstance(true);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 當 Fragment 的 onCreate 方法執行,說明了 Fragment 已經成功新增到了 Activity,
// sHolderFragmentManager 是 HolderFragmentManager類,它的 holderFragmentCreated()方法
// 是將該 Fragment 從 mNotCommittedActivityHolders 或 mNotCommittedFragmentHolders 中移除
// (HolderFragmentManager 的說明,請看下面的註釋)
sHolderFragmentManager.holderFragmentCreated(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onDestroy() {
super.onDestroy();
// 當一個設定了 setRetainInstance(true) 的 Fragment 的 onDestroy 方法被呼叫,
// 證明它依附的 Activity 已經壽終正寢,所以呼叫 mViewModelStore.clear(),
// 前面我們已經說了,這個 clear 方法會呼叫所有 ViewModel 物件的 onCleared 方法
// 並且清空它們,我們可以在 ViewModel 的onCleared 方法做一些處理,以免起來不必要的
// 記憶體洩漏等問題
mViewModelStore.clear();
}
// 該方法用於給外部呼叫,返回 ViewModelStore
@Override
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
// 靜態方法,沒 ViewModelStores.of 方法中被呼叫
// 作用:在 activity 中新增一個 HolderFragment 用於儲存存放了ViewModel物件的ViewModelStore
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
// 靜態方法,沒 ViewModelStores.of 方法中被呼叫
// 作用:在 fragment 中新增一個 HolderFragment 用於儲存存放了ViewModel物件的ViewModelStore
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(Fragment fragment) {
return sHolderFragmentManager.holderFragmentFor(fragment);
}
// 上面的大部分操作都是基於HolderFragmentManager,我們來分析下這個類
@SuppressWarnings("WeakerAccess")
static class HolderFragmentManager {
// 存放還沒被系統正式新增到 Activity 中的 HolderFragment
private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();
// 宣告定義了一個能夠感知 Activity 生命週期的 ActivityLifecycleCallbacks
private ActivityLifecycleCallbacks mActivityCallbacks =
new EmptyActivityLifecycleCallbacks() {
@Override
public void onActivityDestroyed(Activity activity) {
// 當 Activity destroy 的時候,清除 mNotCommittedActivityHolders 中儲存
// 的對應 HolderFragment。前面我們分析了 HolderFragment 的 onCreate 方法中
// 會請一次 mNotCommittedActivityHolders,為什麼在這麼還要多此一舉呢?其實
// 並不是多此一舉,因為 Fragment 有可能還沒建立完,Activity 就夭折了,那這樣子
// HodlerFragment 的 onCreate 就無法呼叫,所以在加多一層清理機制,確保能夠
// 清除掉(不得不感嘆,谷歌官方的嚴謹以及對原始碼的掌控理解能力)
HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
if (fragment != null) {
Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
}
}
};
private boolean mActivityCallbacksIsAdded = false;
private FragmentLifecycleCallbacks mParentDestroyedCallback =
new FragmentLifecycleCallbacks() {
@Override
public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
// 與 mActivityCallbacks 的分析同理
super.onFragmentDestroyed(fm, parentFragment);
HolderFragment fragment = mNotCommittedFragmentHolders.remove(
parentFragment);
if (fragment != null) {
Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
}
}
};
// HolderFragment 的 onCreate 生命週期被回撥,就會呼叫這個方法,清除
// mNotCommittedActivityHolders 或者 mNotCommittedFragmentHolders 中
// 的引用的 HolderFragment
void holderFragmentCreated(Fragment holderFragment) {
Fragment parentFragment = holderFragment.getParentFragment();
if (parentFragment != null) {
mNotCommittedFragmentHolders.remove(parentFragment);
parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
mParentDestroyedCallback);
} else {
mNotCommittedActivityHolders.remove(holderFragment.getActivity());
}
}
private static HolderFragment findHolderFragment(FragmentManager manager) {
if (manager.isDestroyed()) {
throw new IllegalStateException("Can't access ViewModels from onDestroy");
}
Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
throw new IllegalStateException("Unexpected "
+ "fragment instance was returned by HOLDER_TAG");
}
return (HolderFragment) fragmentByTag;
}
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
return holder;
}
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedActivityHolders.get(activity);
if (holder != null) {
return holder;
}
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
holder = createHolderFragment(fm);
// 我們新新增 add 的 Fragment 並不會馬上就執行新增完(也就是說,這個方法執行完成後,馬上再
// 呼叫一次,上面的 findHolderFragment 會返回 null。但是這沒有關係,因為接下來我們還可
// 從 mNotCommittedActivityHolders 獲取到對應的例項),所以我們這裡先把他放在
// mNotCommittedActivityHolders 中。Not Committed 表示 fragment 的 commit 還沒有完成
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
HolderFragment holderFragmentFor(Fragment parentFragment) {
FragmentManager fm = parentFragment.getChildFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedFragmentHolders.get(parentFragment);
if (holder != null) {
return holder;
}
parentFragment.getFragmentManager().registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
holder = createHolderFragment(fm);
// 同上
mNotCommittedFragmentHolders.put(parentFragment, holder);
return holder;
}
}
}複製程式碼
通過上面的註釋,我們已經詳細地對HolderFragment
這個核心類做了分析,總結一下:
HolderFragment
通過設定setRetainInstance(true)
,使得自身能夠不受到螢幕旋轉等configuration changes影響而存活,直到依附的Activity
正常結束。- 因為
HolderFragment
的生命週期,ViewModelStore
物件儲存在HolderFragment
中,而ViewModel
又儲存在ViewModelStore
中,這就是為什麼我們說ViewModel
類能夠讓資料在螢幕旋轉等配置資訊改變導致UI重建的情況下不被銷燬。
總結
ViewModel
的分析就到此為止了,我們主要解決了兩個問題:
- ViewModel是怎樣建立的?
通過呼叫ViewModelProviders.of(this).get(XxxViewModel.class)
或者ViewModelProviders.of(this, mFactory).get(XxxViewModel.class)
返回ViewModel
。最終ViewModel
實際上是由Factory
建立,當我們不傳Factory
引數時,系統預設使用AndroidViewModelFactory
作為Factory
,通過反射生成ViewModel
例項物件返回。
- ViewModel以及儲存在其中的資料是怎樣在螢幕旋轉下依然保留在記憶體中的?
GC垃圾回收機制不會回收被強引用的物件。在開發過程中,我們需要儲存的資料被ViewModel
引用,ViewModel
被ViewModelStore
引用,而ViewModelStore
又被HolderFragment
引用,於是就形成了一條引用鏈:HolderFragment
->ViewModelStore
->ViewModel
->我們想要儲存的資料(最佳實踐是LiveData
)。通過上面HolderFragment
的分析,我們知道HodlerFragment
在建立時,設定了setRetainInstance(true)
,因此它使得自身能夠不受到螢幕旋轉等configuration changes影響而存活,直到依附的Activity
正常結束。
最後,附上一副時序圖供諸位朋友們幫助理解記憶:
初到掘金,人生地不熟,喜歡的朋友,點個贊鼓勵下新手唄~