Lifecycle-arch-ViewModel
距离 Google 发布 Lifecycle 组件已经有一段时间了, 特意尝鲜用了一下, 这里主要记录一下 ViewModel 组件的原理和功能.
ViewModel
用途
ViewModel 用来存储和管理 UI 相关的数据, 在 UI 重建时不需要重建其相应的 ViewModel, 也可以在不同的 Fragment 之间共享一个 ViewModel.
1 | public abstract class ViewModel { |
它本身就是一个抽象类, 可以实现 onCleared() 方法做一些清理工作
实现细节
获取 ViewModel 的方法很简单:
1 | ViewModel viewModel = ViewModelProviders.of(context).get(ViewModel.class); |
通过这个方法去追踪实现即可, 实际代码不多, 就贴个实现过程吧.
context 传入 Fragment
或 FragmentActivity
, 因为他们都可以添加 Fragment. 这里就以 FragmentActivity 为例来说明.
- 创建一个没有 view 的
HolderFragment
,HolderFragment
中通过设置setRetainInstance(true);
实现它在 Activity 重建时能够保存自己的实例 HolderFragment
的ViewModelStores
会维护一个HashMap<String, ViewModel>
用于记录其实例化过的 ViewModel 对象, 并在HolderFragment
的onDestroy()
回调中执行 ViewModel 的onCleared()
方法
这里有一个关于生命周期的细节, 为了防止 Fragment 重复创建或者泄露, Google 对其做了一些保护:
1 | private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>(); |
add Fragment 的流程(以 FragmentActivity 为例):
Application
注册ActivityLifecycleCallbacks
, 在 ActivityonDestroy()
时从 mNotCommittedActivityHolders 中移除未 commit 的HolderFragment
.1
2
3
4
5
6activity.getApplication().registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
public void onActivityDestroyed(Activity activity) {
HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
}
});commit
HolderFragment
到对应 Activity1
2
3
4
5private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
return holder;
}在 HolderFragment 的
onCreate()
生命周期中从 mNotCommittedActivityHolders 中移除自己1
2
3
4
5
6
7
8
9
10void holderFragmentCreated(Fragment holderFragment) {
Fragment parentFragment = holderFragment.getParentFragment();
if (parentFragment != null) {
mNotCommittedFragmentHolders.remove(parentFragment);
parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
mParentDestroyedCallback);
} else {
mNotCommittedActivityHolders.remove(holderFragment.getActivity());
}
}
这样可以防止重复调用导致多次创建 HolderFragment, 也可以在 Fragment 创建后移除不必要的备份, 更可以防止内存泄露.