Android 架构组件 —— Lifecycle-aware
本次将对Lifecycle-aware Components
的最后一个组件ViewModel
进行分析。
ViewModel
主要用于在Activity存活的生命周期内对UI中数据的保存以及在Activity配置更改(如屏幕旋转等)重新创建时对数据的保存。且由于ViewModel
自身也包含生命周期感知,可以确保其中的异步调用在其生命周期结束后销毁异步调用以解决可能的内存泄漏。
Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.(from Android Developers)
ViewModel对象初始化
ViewModel
的设计采用工厂模式,通过ViewModelProviders
创建一个用于存储ViewModel
的ViewModelProvider
:
public class ViewModelProviders {
...
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
initializeFactoryIfNeeded(checkApplication(checkActivity(fragment)));
return new ViewModelProvider(ViewModelStores.of(fragment), sDefaultFactory);
}
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
initializeFactoryIfNeeded(checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
}
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) {
checkApplication(checkActivity(fragment));
return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@NonNull Factory factory) {
checkApplication(activity);
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
...
}
四个方法的实质都是通过其载体(Activity或Fragment)创建一个ViewModelStores
对象来和传入的工厂对象组成ViewModelProvider
对象:
//ViewModelStores.java
public class ViewModelStores {
private ViewModelStores() {
}
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
return holderFragmentFor(activity).getViewModelStore();
}
@MainThread
public static ViewModelStore of(@NonNull Fragment fragment) {
return holderFragmentFor(fragment).getViewModelStore();
}
}
//HolderFragment.java
public class HolderFragment extends Fragment {
...
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(Fragment fragment) {
return sHolderFragmentManager.holderFragmentFor(fragment);
}
...
static class sHolderFragmentManager{
...
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;
}
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;
}
}
}
从上述流程看出,最终调用了HolderFragmentManager
的holderFragmentFor
方法,无论传进来的是Activity还是Fragment,都创建了一个依托于它的Fragment,用来实际存储ViewModel
对象。由于创建的HolderFragment在其载体配置发生变化的时候并不会被销毁(setRetainInstance(true)),由此实现了配置变化时仍能保存对应具体信息的效果。
生成的ViewModelProvider
对象结构较简单,仅提供了get
方法用于取值:
取之方法最终都是调用了如下方法:
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;
}
首先直接从ViewModelStore
中尝试取出对应ViewModel
对象,若为空则调用工厂方法对ViewModel
进行创建并将其存储到ViewModelStore
中去。因此,在Activity和Fragment中若使用同一对象初始化ViewModelProvider
取出的对象是同一对象,实现了Activity和Fragment或Fragment之间通过ViewModel进行交互并可以忽略对方生命周期效果。
同时官方不推荐在ViewModel
中注册监听LiveData
或其他有关生命周期的引用,因为会导致可能的内存泄漏问题。但在需要使用的时候还是提供了解决方法:
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() {
}
}
在每个ViewModel
销毁时都会调用onCleared()
方法,在其中释放对应内容以防止内存泄漏的发生。
小结
本次ViewModel
分析到此结束,其中的精华应该在于使用Fragment进行数据的保存和恢复以及共用,从而减少侵入性。
整个Lifecycle-aware Components
工作流程在理解了之前Lifecycle
和LiveData
和本篇之后,应该有了一个明确的流程,至此Lifecycle-aware Components
基础框架分析完毕。