如果還不清楚什么是ViewModel,可以看下[譯] Architecture Components 之 ViewModel 這個(gè)系列的文章,翻譯自Android Developer的官方文章。
ViewModel 類(lèi)是被設(shè)計(jì)用來(lái)存儲(chǔ)和管理 UI 相關(guān)的數(shù)據(jù),主要實(shí)現(xiàn)了兩個(gè)功能:
- 在配置更改(如:屏幕旋轉(zhuǎn))時(shí)數(shù)據(jù)可以保留下來(lái)。
- 在 Fragment 之間共享數(shù)據(jù)。
接下來(lái)會(huì)通過(guò)分析源碼的方式來(lái)看看是如何實(shí)現(xiàn)這兩個(gè)功能的。
我們先來(lái)找到ViewModel這個(gè)類(lèi)
ViewModel
public abstract class ViewModel {
/**
* This method will be called when this ViewModel is no longer used and will be destroyed.
* <p>
* It is useful when ViewModel observes some data and you need to clear this subscription to
* prevent a leak of this ViewModel.
*/
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
}
發(fā)現(xiàn)只是一個(gè)抽象類(lèi),并且只有一個(gè)空實(shí)現(xiàn)的方法,說(shuō)明實(shí)現(xiàn)特殊功能的代碼一定在其他地方。
看過(guò)官方介紹的應(yīng)該知道,ViewModel是通過(guò)ViewModelProvider創(chuàng)建的:
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// 更新 UI
});
}
}
那我們從這里開(kāi)始分析,通過(guò)調(diào)用ViewModelProviders.of(this).get(MyViewModel.class)是如何獲取到ViewModel的那?我們來(lái)看ViewModelProviders的of()方法(of方法重載還有Fragment,這里我們只分析Activity,F(xiàn)ragment與activity如出一轍):
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
initializeFactoryIfNeeded(checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
}
@SuppressLint("StaticFieldLeak")
private static DefaultFactory sDefaultFactory;
private static void initializeFactoryIfNeeded(Application application) {
if (sDefaultFactory == null) {
sDefaultFactory = new DefaultFactory(application);
}
}
private static Application checkApplication(Activity activity) {
Application application = activity.getApplication();
if (application == null) {
throw new IllegalStateException("Your activity/fragment is not yet attached to "
+ "Application. You can't request ViewModel before onCreate call.");
}
return application;
}
ViewModelProviders.of()方法返回了一個(gè)ViewModelProvider對(duì)象,該對(duì)象需要兩個(gè)參數(shù):ViewModelStore、Factory。通過(guò)命名,我們可以猜測(cè)ViewModelStore是一個(gè)ViewModel的倉(cāng)庫(kù),用于緩存ViewModel,F(xiàn)actory是工廠類(lèi),用于創(chuàng)建ViewModel實(shí)例。獲取到ViewModelProvider對(duì)象后,又調(diào)用了它的get方法就獲取到ViewModel對(duì)象,來(lái)看下這個(gè)方法:
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
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 {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
ViewModelProvider類(lèi)中將構(gòu)造的參數(shù)ViewModelStore和Factory作為成員變量,get方法先是從mViewModelStore.get中獲取,如果沒(méi)有獲取到則通過(guò)Factory創(chuàng)建一個(gè)ViewModel實(shí)例,并放入ViewModelStore中,這種使用方式更加驗(yàn)證了上面我們的猜測(cè),之后會(huì)仔細(xì)分析ViewModelStore以及Factory。
既然有一個(gè)ViewModel的緩存ViewModelStore,那第一個(gè)功能:在配置更改(如:屏幕旋轉(zhuǎn))時(shí)數(shù)據(jù)可以保留下來(lái),就很好理解了。只要讓緩存在Activity配置更改重建是存活下來(lái),那重建后獲取的ViewModel就是之前緩存的那個(gè)了。
接下的問(wèn)題便是: ViewModelStore存放在哪里可以保證在Activity配置更改重建是存活下來(lái)?
ViewModelStore
字面意思即為ViewModel的倉(cāng)庫(kù)
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);
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
這個(gè)很簡(jiǎn)單,也很好理解,僅僅是一個(gè)HashMap用于存放ViewModel,提供放入,獲取,清空的方法。
我們回到ViewModelProviders.of()方法來(lái),這里是通過(guò)ViewModelStores.of(activity)獲取到的ViewModelStore對(duì)象的,我們繼續(xù)進(jìn)入這個(gè)方法:
import static android.arch.lifecycle.HolderFragment.holderFragmentFor;
public class ViewModelStores {
private ViewModelStores() {
}
public static ViewModelStore of(@NonNull FragmentActivity activity) {
return holderFragmentFor(activity).getViewModelStore();
}
}
注意到通過(guò)靜態(tài)引入的方法調(diào)用了HolderFragment的holderFragmentFor ()方法,接著找到HolderFragment:
HolderFragment
public class HolderFragment extends Fragment {
...//去除了framgent相關(guān)的代碼,只保留activity相關(guān)
private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();
public static final String HOLDER_TAG =
"android.arch.lifecycle.state.StateProviderHolderFragment";
private ViewModelStore mViewModelStore = new ViewModelStore();
public HolderFragment() {
setRetainInstance(true);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sHolderFragmentManager.holderFragmentCreated(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public void onDestroy() {
super.onDestroy();
mViewModelStore.clear();
}
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
static class HolderFragmentManager {
private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
private ActivityLifecycleCallbacks mActivityCallbacks =
new EmptyActivityLifecycleCallbacks() {
@Override
public void onActivityDestroyed(Activity activity) {
HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
if (fragment != null) {
Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
}
}
};
private boolean mActivityCallbacksIsAdded = false;
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);
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
}
這個(gè)類(lèi)就是ViewModel的核心類(lèi)了,所有的功能都是通過(guò)該類(lèi)來(lái)實(shí)現(xiàn)的,注意看好啦~
HolderFragment.holderFragment()方法直接返回了sHolderFragmentManager.holderFragmentFor(activity)的結(jié)果。而HolderFragmentManager的holderFragmentFor方法實(shí)際上就是創(chuàng)建了一個(gè)HolderFragment的實(shí)例,并添加到參數(shù)activity中,為了避免重復(fù)添加,先是調(diào)用 findHolderFragment(fm) 看看能否找到已添加HolderFragment,如果沒(méi)有的話再?gòu)木彺娴腗ap中找,還是沒(méi)有話才去創(chuàng)建一個(gè)新的實(shí)例,放入緩存的Map,并返回這個(gè)對(duì)象,繼而調(diào)用getViewModelStore()獲取viewModelStore實(shí)例。
我們找到了ViewModelStore存放位置,是在HolderFragment中,那它如何保證在Activity配置更改重建是存活下來(lái)的?其實(shí)關(guān)鍵代碼就是Fragment的一個(gè)方法:
/**
* Control whether a fragment instance is retained across Activity
* re-creation (such as from a configuration change). This can only
* be used with fragments not in the back stack. If set, the fragment
* lifecycle will be slightly different when an activity is recreated:
* <ul>
* <li> {@link #onDestroy()} will not be called (but {@link #onDetach()} still
* will be, because the fragment is being detached from its current activity).
* <li> {@link #onCreate(Bundle)} will not be called since the fragment
* is not being re-created.
* <li> {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} <b>will</b>
* still be called.
* </ul>
*/
setRetainInstance(true);
就是這個(gè)方法保證了activity因配置更改重建時(shí),該fragment的實(shí)例不會(huì)銷(xiāo)毀,重建后的Activity還是使用該實(shí)例。
創(chuàng)建HolderFragment 的過(guò)程還有很多細(xì)節(jié)。
需要注意的是HolderFragmentManager是聲明在HolderFragment中的static成員,因此會(huì)隨著HolderFragment的首次加載創(chuàng)建實(shí)例,只存在一個(gè)實(shí)例并永遠(yuǎn)在內(nèi)存中,緩存的map是HolderFragmentManager的成員變量,也會(huì)永遠(yuǎn)在內(nèi)存中,而HolderFragment可以創(chuàng)建多個(gè)實(shí)例,所以對(duì)于不再需要的HolderFragment實(shí)例,需要及時(shí)從map中移除。
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
這段代碼是通過(guò)Application的registerActivityLifecycleCallbacks注冊(cè)一個(gè)全局Activity生命周期的回調(diào),任何Activity觸發(fā)了生命周期都會(huì)在mActivityCallbacks中回調(diào)對(duì)應(yīng)的方法。HolderFragment的源碼中就是通過(guò)該回調(diào),在綁定HolderFragment的Activity觸發(fā)onDestroy方法后移除map中的緩存。
一開(kāi)始我以為HolderFragmentManager會(huì)緩存HolderFragment直到依附的activity銷(xiāo)毀才會(huì)移除緩存,但后來(lái)注意到在HolderFragment的onCreate方法中調(diào)用了sHolderFragmentManager.holderFragmentCreated(this);直接移除了緩存。因此,這個(gè)緩存僅僅是從HolderFragment的add方法調(diào)用到onCreate方法執(zhí)行為止?;蛘遖dd了Fragment但是還沒(méi)有添加到Activity執(zhí)行onCreate方法,依附的Activity就銷(xiāo)毀了,也會(huì)回調(diào)mActivityCallbacks的onDestroy方法移除HolderFragment的緩存。我想了很久也沒(méi)有想到這個(gè)緩存的使用場(chǎng)景,好像這個(gè)緩存是沒(méi)有意義的。
2017.12.27 補(bǔ)充:
經(jīng)過(guò)JessYan的提點(diǎn),我意識(shí)到HolderFragment的緩存是很有意義的,如果沒(méi)有這個(gè)緩存,在連續(xù)調(diào)用兩次獲取ViewModel時(shí),F(xiàn)ragment還沒(méi)有添加執(zhí)行onCreate,那這樣就會(huì)創(chuàng)建兩個(gè)HolderFragment實(shí)例了。并且這種情況在兩個(gè)Fragment之間發(fā)生的話,獲取到的就是不同ViewModel實(shí)例,也就無(wú)法實(shí)現(xiàn)Fragment間通訊了。我用as3.0 的Android profiler驗(yàn)證了這種情況,確實(shí)創(chuàng)建了兩個(gè)實(shí)例!
Factory
即為創(chuàng)建ViewModel的工廠類(lèi),是一個(gè)接口,我們可以實(shí)現(xiàn)這個(gè)接口定義自己的ViewModel工廠。
/**
* Implementations of {@code Factory} interface are responsible to instantiate ViewModels.
*/
public interface Factory {
/**
* Creates a new instance of the given {@code Class}.
* <p>
*
* @param modelClass a {@code Class} whose instance is requested
* @param <T> The type parameter for the ViewModel.
* @return a newly created ViewModel
*/
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
上面of()使用的sDefaultFactory默認(rèn)工廠:
public static class DefaultFactory extends ViewModelProvider.NewInstanceFactory {
private Application mApplication;
/**
* Creates a {@code DefaultFactory}
*
* @param application an application to pass in {@link AndroidViewModel}
*/
public DefaultFactory(@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);
}
}
public static class NewInstanceFactory implements Factory {
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
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);
}
}
}
DefaultFactory可以創(chuàng)建AndroidViewModel的對(duì)象,調(diào)用它AndroidViewModel(@NonNull Application application)構(gòu)造創(chuàng)建實(shí)例,如果不是AndroidViewModel.class則調(diào)用父類(lèi)NewInstanceFactory的create方法調(diào)用ViewModel無(wú)參數(shù)的構(gòu)造。
如果你的ViewModel實(shí)例的創(chuàng)建需要其他參數(shù),則要自己實(shí)現(xiàn)Factory復(fù)寫(xiě)create。
總結(jié)
ViewModelProviders.of()提供ViewModelProvider,ViewModelProvider通過(guò)ViewModelStore和Factory管理和創(chuàng)建ViewModel,ViewModelStore的引用存儲(chǔ)在向目標(biāo)Activity/Fragment中添加的無(wú)界面HolderFragment中,并通過(guò)setRetainInstance(true);以保證在Activity配置更改重建是存活下來(lái)。
關(guān)于第二條功能:在 Fragment 之間共享數(shù)據(jù)也很好理解了,在同一個(gè)Activity的不同F(xiàn)ragment種使用ViewModelProviders.of()時(shí),參數(shù)需要傳入Activity對(duì)象,第一次獲取ViewModel時(shí)會(huì)創(chuàng)建一個(gè)新對(duì)象,而另一個(gè)Fragment獲取相同ViewModel時(shí),則會(huì)從ViewModelStore的緩存中獲取,兩個(gè)Fragment持有的時(shí)同一個(gè)ViewModel對(duì)象,就能實(shí)現(xiàn)Fragment之間通訊了。但是這種通訊的前途是必須在同一個(gè)Activity中。