Lifecycle-arch-ViewModel

距离 Google 发布 Lifecycle 组件已经有一段时间了, 特意尝鲜用了一下, 这里主要记录一下 ViewModel 组件的原理和功能.

ViewModel

用途

ViewModel 用来存储和管理 UI 相关的数据, 在 UI 重建时不需要重建其相应的 ViewModel, 也可以在不同的 Fragment 之间共享一个 ViewModel.

1
2
3
4
5
6
public abstract class ViewModel {
protected void onCleared() {

}
}

它本身就是一个抽象类, 可以实现 onCleared() 方法做一些清理工作

实现细节

获取 ViewModel 的方法很简单:

1
ViewModel viewModel = ViewModelProviders.of(context).get(ViewModel.class);

通过这个方法去追踪实现即可, 实际代码不多, 就贴个实现过程吧.

context 传入 FragmentFragmentActivity, 因为他们都可以添加 Fragment. 这里就以 FragmentActivity 为例来说明.

  1. 创建一个没有 view 的 HolderFragment, HolderFragment 中通过设置 setRetainInstance(true); 实现它在 Activity 重建时能够保存自己的实例
  2. HolderFragmentViewModelStores 会维护一个 HashMap<String, ViewModel> 用于记录其实例化过的 ViewModel 对象, 并在 HolderFragmentonDestroy() 回调中执行 ViewModel 的 onCleared() 方法

这里有一个关于生命周期的细节, 为了防止 Fragment 重复创建或者泄露, Google 对其做了一些保护:

1
private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();

add Fragment 的流程(以 FragmentActivity 为例):

  1. Application 注册 ActivityLifecycleCallbacks, 在 Activity onDestroy() 时从 mNotCommittedActivityHolders 中移除未 commit 的 HolderFragment.

    1
    2
    3
    4
    5
    6
    activity.getApplication().registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
    @Override
    public void onActivityDestroyed(Activity activity) {
    HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
    }
    });
  2. commit HolderFragment 到对应 Activity

    1
    2
    3
    4
    5
    private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
    HolderFragment holder = new HolderFragment();
    fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
    return holder;
    }
  3. 在 HolderFragment 的 onCreate() 生命周期中从 mNotCommittedActivityHolders 中移除自己

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void holderFragmentCreated(Fragment holderFragment) {
    Fragment parentFragment = holderFragment.getParentFragment();
    if (parentFragment != null) {
    mNotCommittedFragmentHolders.remove(parentFragment);
    parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
    mParentDestroyedCallback);
    } else {
    mNotCommittedActivityHolders.remove(holderFragment.getActivity());
    }
    }

这样可以防止重复调用导致多次创建 HolderFragment, 也可以在 Fragment 创建后移除不必要的备份, 更可以防止内存泄露.