前言
最近一個(gè)月主要實(shí)現(xiàn)了IM功能,其中UI框架使用了ViewModel和LiveData的存儲(chǔ)和通知機(jī)制,實(shí)現(xiàn)后代碼簡潔易于維護(hù)。
感慨于Android arch components控件強(qiáng)大同時(shí),需要順帶分析一波其中源碼實(shí)現(xiàn)。今天先來分析一下ViewModel的源碼實(shí)現(xiàn)。
ViewModel簡介
ViewModel是通過關(guān)聯(lián)生命周期的方式來存儲(chǔ)和管理跟UI相關(guān)的數(shù)據(jù)。即使configuration發(fā)生變化,在ViewModel中存放的數(shù)據(jù)是不會(huì)被銷毀的。
沒使用ViewModel的時(shí)候,如果系統(tǒng)Configuration發(fā)生變化,我們的Activity會(huì)被銷毀重建,導(dǎo)致Activity中的UI數(shù)據(jù)丟失。為了規(guī)避這個(gè)問題,我們只能在onSaveInstanceState()將UI數(shù)據(jù)進(jìn)行保存,在onCreate方法中判斷savedInstanceState中是否有我們存儲(chǔ)的數(shù)據(jù)。
有了ViewModel之后,我們只需要將數(shù)據(jù)存儲(chǔ)到ViewModel即可,ViewModel中的數(shù)據(jù)不會(huì)隨著Activity的銷毀重建而消失。同時(shí),如果不同的Fragment使用相同的Activity對象來獲取ViewModel,可以輕易的實(shí)現(xiàn)數(shù)據(jù)共享和通信。
使用ViewModel的例子:
// 自定義一個(gè)ViewModel,存儲(chǔ)一個(gè)字符串
public class TestViewModel extends ViewModel {
public String content;
@Override
protected void onCleared() {
// 數(shù)據(jù)清理工作
content = null;
}
}
// 在Activity中獲取并使用ViewModel
TestViewModel viewModel = ViewModelProviders.of(activity).get(TestViewModel.class);
Log.d("tag", viewModel.content);
三個(gè)問題
- ViewModel是如何創(chuàng)建出來的?
- 為什么不同的Fragment使用相同的Activity對象來獲取ViewModel,可以輕易的實(shí)現(xiàn)ViewModel共享?
- ViewModel為什么在Activity銷毀重建時(shí)不會(huì)被銷毀回收?
我個(gè)人習(xí)慣,看源碼時(shí)候總是要帶著問題去分析理解,這樣才會(huì)有所收獲。
源碼分析
ViewModel是如何創(chuàng)建出來的?
通過示例代碼,去掉鏈?zhǔn)秸{(diào)用后,我們可以看到ViewModel是通過如下兩步創(chuàng)建出來的:
// 1\. 創(chuàng)建ViewModelProvider
ViewModelProvider viewModelProvider = ViewModelProviders.of(activity);
// 2\. 通過反射獲取ViewModel
TestViewModel viewModel = viewModelProvider.get(TestViewModel.class);
創(chuàng)建ViewModelProvider
先看下第一步的源碼實(shí)現(xiàn):
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) {
if (factory == null) {
// 如果傳入的對象創(chuàng)建工廠類為null,則使用默認(rèn)的AndroidViewModelFactory來創(chuàng)建對象
factory = AndroidViewModelFactory.getInstance(application);
}
// 創(chuàng)建一個(gè)ViewModelProvider
return new ViewModelProvider(ViewModelStores.of(activity), (Factory)factory);
}
源碼中,我們發(fā)現(xiàn)創(chuàng)建一個(gè)ViewModelProvider需要傳入兩個(gè)參數(shù):ViewModelStore和Factory。我們先看下Factory的實(shí)現(xiàn)。
Factory
Factory顧名思義,定義了創(chuàng)建ViewModel的行為接口。里面只有一個(gè)create方法,用于子類自行決定如何實(shí)現(xiàn)一個(gè)ViewModel對象的創(chuàng)建。
public interface Factory {
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
同時(shí),ViewModelProvider源碼內(nèi)部也提供了兩個(gè)默認(rèn)Factory實(shí)現(xiàn):NewInstanceFactory和AndroidViewModelFactory。
// 直接反射Class對象的無參構(gòu)造函數(shù)來創(chuàng)建ViewModel
public static class NewInstanceFactory implements Factory {
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
try {
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);
}
}
}
// 1\. 如果對象繼承自AndroidViewModel,發(fā)射調(diào)用帶Application參數(shù)的構(gòu)造函數(shù)創(chuàng)建ViewModel對象;
// 2\. 如果對象不繼承自AndroidViewModel,則直接調(diào)用父類,即調(diào)用Class的無參構(gòu)造函數(shù)創(chuàng)建ViewModel對象。
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) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
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);
}
}
return super.create(modelClass);
}
}
啟示:我們自定義的ViewModel對象如果構(gòu)造函數(shù)中需要其他各種參數(shù),我們只需要?jiǎng)?chuàng)建一個(gè)自定義的Factory類,然后調(diào)用該class的有參構(gòu)造函數(shù)進(jìn)行創(chuàng)建即可。
ViewModelStore
ViewModelStore就是個(gè)HashMap,通過key來獲取ViewModel對象。
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.get(key);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
mMap.put(key, viewModel);
}
final ViewModel get(String key) {
return mMap.get(key);
}
}
ViewModelProvider
了解了Factory實(shí)現(xiàn)和ViewModelStore實(shí)現(xiàn)后,我們來看一下ViewModelProvider的get方法是如何創(chuàng)建ViewModel對象的。
public class ViewModelProvider {
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
}
ViewModleProvider的get方法實(shí)現(xiàn)也比較簡單,總結(jié)一下就是:
- 使用ViewModel Class的canonicalName作為ViewModel在ViewModelStore中的唯一標(biāo)識。
- 通過唯一標(biāo)識,先查詢一下ViewModelStore中是否有該ViewModel對象,如果有則直接返回。
- 如果ViewModelStore中沒有該ViewModel對象,則通過Factory工廠類反射創(chuàng)建出ViewModel對象,存入ViewModelStore中,并返回給調(diào)用者。
小結(jié)
至此,第一個(gè)問題ViewModel是如何創(chuàng)建出來的已經(jīng)分析完畢。接下來,我們看第二個(gè)問題。
為什么不同的Fragment使用相同的Activity對象來獲取ViewModel,可以輕易的實(shí)現(xiàn)ViewModel共享?
講道理,如果同學(xué)們仔細(xì)看了ViewModel的創(chuàng)建流程,這個(gè)問題自然迎刃而解。
因?yàn)椴煌腇ragment使用相同的Activity對象來獲取ViewModel,在創(chuàng)建ViewModel之前都會(huì)先從Activity提供的ViewModelStore中先查詢一遍是否已經(jīng)存在該ViewModel對象。所以我們只需要先在Activity中同樣調(diào)用一遍ViewModel的獲取代碼,即可讓ViewModel存在于ViewModelStore中,從而不同的Fragment可以共享一份ViewModel了。
ViewModel為什么在Activity銷毀重建時(shí)不會(huì)被銷毀回收?
在看這個(gè)問題之前,我們回到ViewModelProviders.of()源碼中:
public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) {
if (factory == null) {
// 如果傳入的對象創(chuàng)建工廠類為null,則使用默認(rèn)的AndroidViewModelFactory來創(chuàng)建對象
factory = AndroidViewModelFactory.getInstance(application);
}
// 創(chuàng)建一個(gè)ViewModelProvider
return new ViewModelProvider(ViewModelStores.of(activity), (Factory)factory);
}
ViewModelProvider獲取ViewModelStore是通過ViewModelStores.of(activity)實(shí)現(xiàn)的。我們先看一下這個(gè)ViewModelStores做了什么操作。
ViewModelStores
看名字又像是一個(gè)封裝好的工廠類??聪略创a:
public static ViewModelStore of(@NonNull FragmentActivity activity) {
return activity instanceof ViewModelStoreOwner ? ((ViewModelStoreOwner)activity).getViewModelStore() : HolderFragment.holderFragmentFor(activity).getViewModelStore();
}
通過源碼可以發(fā)現(xiàn),如果Activity是ViewModelStoreOwner的實(shí)現(xiàn)類,則直接通過activity獲取ViewModelStore,如果不是,則通過HolderFragment.holderFragmentFor(activity).getViewModelStore()來獲取。
通過查看FragmentActivity源碼,發(fā)現(xiàn)其已經(jīng)是實(shí)現(xiàn)了ViewModelStoreOwner接口。
public class FragmentActivity extends BaseFragmentActivityApi16 implements
ViewModelStoreOwner,
ActivityCompat.OnRequestPermissionsResultCallback,
ActivityCompat.RequestPermissionsRequestCodeValidator {
}
所以這里我們已經(jīng)不需要理會(huì)HolderFragment了,很多分析ViewModel源碼的文章都會(huì)花很多篇幅分析HolderFragment,我實(shí)在是搞不懂為什么要這種操作。(初步懷疑是互相抄襲。。.)
雖然FragmentActivity實(shí)現(xiàn)了ViewModelStoreOwner接口,能夠提供ViewModelStore,但是ViewModelStore是如何跟Activity生命周期關(guān)聯(lián)起來的呢?
FragmentActivity中ViewModelStore的生命周期處理
搜索了一下FragmentActivity中關(guān)于ViewModelStore的調(diào)用,發(fā)現(xiàn)這里的實(shí)現(xiàn)應(yīng)該跟生命周期處理有關(guān)。

google搜索了一下Activity的onRetainNonConfigurationInstance的作用:大部分同學(xué)知道Activity因?yàn)閏onfiguration變化銷毀和重建時(shí)會(huì)調(diào)用onSaveInstanceState和onRestoreInstanceState。與此同時(shí),Activity其實(shí)還會(huì)回調(diào)onRetainNonConfigurationInstance和getLastNonConfigurationInstance方法。
onRetainNonConfigurationInstance和onSaveInstanceState作用相同,用來保存UI相關(guān)變量,當(dāng)Activity意外銷毀時(shí),Activity的ViewModelStore對象就是在這里進(jìn)行了保存。
那什么時(shí)機(jī)進(jìn)行的恢復(fù)呢?
當(dāng)Activity的onCreate調(diào)用時(shí),會(huì)調(diào)用getLastNonConfigurationInstance,獲取之前保存的ViewModelStore,如果ViewModelStore不為空,就進(jìn)行賦值。這里進(jìn)行了ViewModelStore的恢復(fù)。

小結(jié)
這里我們又學(xué)到了Activity的兩個(gè)跟生命周期相關(guān)的函數(shù)調(diào)用:onRetainNonConfigurationInstance和getLastNonConfigurationInstance。
- Activity實(shí)現(xiàn)了ViewModelStoreOwner接口,創(chuàng)建了ViewModelStore對象。
- 當(dāng)Activity意外銷毀時(shí),onRetainNonConfigurationInstance函數(shù)被回調(diào),在此函數(shù)中對ViewModelStore對象進(jìn)行了保存。
- 當(dāng)Activity重建時(shí),onCreate方法中會(huì)先獲取getLastNonConfigurationInstance,如果其中的ViewModelStore對象不為空,就直接引用,不再重新創(chuàng)建ViewModelStore對象了。
總結(jié)
三個(gè)問題分析完畢,相信大家已經(jīng)對ViewModel的實(shí)現(xiàn)原理比較熟悉了。建議大家以后學(xué)習(xí)源碼時(shí),也帶著問題去分析思考,事半功倍。