Android 官方架构组件(三)——ViewModel

栏目: IOS · Android · 发布时间: 5年前

内容简介:初到掘金,人生地不熟,喜欢的朋友,点个赞鼓励下新手呗~参考文章:https://developer.android.google.cn/topic/libraries/architecture/viewmodel

初到掘金,人生地不熟,喜欢的朋友,点个赞鼓励下新手呗~

参考文章:

https://developer.android.google.cn/topic/libraries/architecture/viewmodel

https://mp.weixin.qq.com/s/thoXHuXHC3sV90IFttHfXw

https://blog.csdn.net/gaugamela/article/details/56280384

ViewModel 类主要用来存储和管理与 UI 相关的数据,它能够让数据在屏幕旋转等配置信息改变导致 UI 重建的情况下不被销毁。

ViewModel生命周期

ViewModel 对象存活在系统中不被回收的时间是由创建 ViewModel 传递给 ViewModelProviderLifecycle 决定的。 ViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 生命周期结束。对于 Activity ,是在Activity destroy时;而对于 Fragment ,是在Fragment detach时。

下图说明了 Activity 经历屏幕旋转直到最终destroyed掉这整个过程中所经历的各个生命周期。该图还在关联的 Activity 生命周期的旁边显示了 ViewModel 的生命周期。

我们可以看出, ViewModel 的生命周期贯穿 Activity 始终,直到 Activity 正常结束,并不会因为屏幕旋转等系统原因而导致 ViewModel 生命周期提前结束。同理 Fragment 对于 ViewModel 也一样。

                Android 官方架构组件(三)——ViewModel

本文,我们不讨论 ViewModel 的使用,而是直接分析它的原理。

ViewModel原理分析

我们分析源码的时候要带着明确目的带着问题去分析,从小见大,一个一个小问题解决,无头苍蝇似的扑进源码中,可能事倍功半。

在分析 ViewModel 源码之前,我们先介绍一下 ViewModel 组件中重要的几个类:

  • ViewModel、 ViewModelProvider、 HolderFragment、 ViewModelStore

Android 官方架构组件(三)——ViewModel

上面的类图简单地描述出了这几个类的作用以及关系,算是一个小概括,下面,我们直接进入源码分析它们具体的实现,以及它们是如何联系起来的。

(在这里默认大家已经知道了 ViewModel 的使用)我们知道ViewModel实例的创建是通过 ViewModelProviders.of(this).get(XxxViewModel.class) 生成的,这行代码可以分为两个步骤:

  • 第一步:通过 ViewModelProviders.of(this) 生成 ViewModelProvider 对象;
  • 第二步:通过 viewModelProvider.get(XxxViewModel.class) 生成相对 ViewModel 对象。

下面我们的源码就针对这两个步骤分析一下 ViewModel 架构中重要的几个类。

ViewModelProvider

ViewModelProvider 是通过 ViewModelProviders.of(this) 生成的,我们进入源码看看:

public static ViewModelProvider of(@NonNull FragmentActivity activity) {
    return of(activity, null);
}

public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) {
    Application application = checkApplication(activity);
    if (factory == null) {
        // 上面的类图,我们已经说了,生成 ViewModelProvider 实例的时候,如果 factory 传 null,
        // 系统会默认使用 AndroidViewModelFactory 作为 ViewModel 的生产类
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }

    // 实例化创建一个 ViewModelProvider 对象返回
    return new ViewModelProvider(ViewModelStores.of(activity), factory);
}复制代码

可以看到, ViewModelProviders.of() 最终会 new 一个 ViewModelProvider 对象返回。在创建 ViewModelProvider 的时候,需要传入两个参数, ViewModelStore 以及 Factory 。在这里,我们先不讨论 ViewModelStores.of(activity) 是如何实例化返回 ViewModelStore 对象的,在后面,我们会说到。

先来看一下 Factory 类,它的定义很简单:

public interface Factory {
    // 只有一个 create 方法需要重写,这个方法就返回 ViewModel 对象,
    // 我们可以选择默认使用 AndroidViewModelFactory,也可以自定义 Factory
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}复制代码

当我们传入的factory参数为null的时候,会默认使用 AndroidViewModelFactory

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) {

        // 当 modelClass 类继承自 AndroidViewModel
        if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
            //noinspection TryWithIdenticalCatches
            try {
                // 调用 modelClass 类中带有 Application 参数的构造方法创建一个 ViewMode 返回
                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);
            }
        }

        // 如果 modelClass 类不是继承自 AndroidViewModel,调用 AndroidViewModelFactory 的
        // 父类 NewInstanceFactory 的 onCreate 方法生成 ViewModel 对象返回
        return super.create(modelClass);
    }
}复制代码

AndroidViewModelFactory 的父类 NewInstanceFactory 也是非常简单:

public static class NewInstanceFactory implements Factory {

    @SuppressWarnings("ClassNewInstance")
    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        //noinspection TryWithIdenticalCatches
        try {
            // 直接通过反射调用 modelClass 类的无参构造函数实例化一个 ViewModel 对象返回
            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);
        }
    }
}复制代码

根据上面对 Factory 的分析, 在传入的factory参数为null的前提下 ,我们可以得出以下结论:

  • 如果我们自定义的model继承自 ViewModel ,需要有一个默认无参的构造方法;
  • 如果我们自定义的model继承自 AndroidViewModel ,必须要有一个以 Application 为唯一参数的构造函数。

当然我们也可以自定义 Factory ,在这里就不讨论了,广大聪明的读者才是最法力无边的~

ViewModelStore

上面我们知道了在构造 ViewModelProvider 的时候,会通过 ViewModelStores.of() 方法获取到一个 ViewModelStore 对象。 ViewModelStores 类是用于提供返回 ViewModelStore 对象的,下面我们来看看 ViewModelStores.of() 究竟做了什么?

public class ViewModelStores {

    private ViewModelStores() {
    }

    @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull FragmentActivity activity) {

        // 开发者可以选择自己让 Activity 继承 ViewModelStoreOwner,然后实现 getViewModelStore 方法
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        
        // holderFragmentFor(activity)方法返回继承了 ViewModelStoreOwner 的 HolderFragment 实例,
        // 调用这个 HolderFragment 对象的 getViewModelStore() 即可以拿到 ViewModelStore 实例。
        return holderFragmentFor(activity).getViewModelStore();
    }

    @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull Fragment fragment) {
        // 同理,fragment 也可以继承 ViewModelStoreOwner ,实现 getViewModelStore 方法
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        // 同上
        return holderFragmentFor(fragment).getViewModelStore();
    }
}复制代码

可以看出, ViewModelStores.of() 方法主要就是从 ViewModelStoreOwner 对象中获取 ViewModelStore 对象。至于 holderFragmentFor() 方法究竟做了什么?我们下面在继续分析,现在,先看看 ViewModelStore

public class ViewModelStore {
    
    // 用 HashMap 存储 ViewModel 对象
    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    // 新添 ViewModel
    final void put(String key, ViewModel viewModel) {
        // 如果对应 key 的 ViewModel 已经存在,那么覆盖它,并且调用它的 onCleared 方法
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }
    
    // 获取指定 key 的 ViewModel
    final ViewModel get(String key) {
        return mMap.get(key);
    }
    
    // 调用所有 ViewModel 的 onCleared 方法,并且清空整个 HashMap
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
}复制代码

ViewModelStore 的实现很简单,主要的作用就是对 ViewModel 进行存储管理,通过一个 HashMap 保存了所有的 ViewModel ,分别通过 put 方法以及 get 方法添加和获取 ViewModel ,通过 clear 方法遍历调用所有 ViewModelonCleared 方法并且清空map。

接下来,我们来看看最核心的一个类, HolderFragment

HolderFragment

前面我们分析 ViewModelStores.of() 方法的时候,提到过调用静态方法 holderFragmentFor() 方法能够返回一个继承了 ViewModelStoreOwnerHolderFragment 实例,现在我们就来看看 HolderFragment 这个类究竟是何方神圣?为什么当 Activity 由于屏幕旋转等被系统销毁时,这个 Fragment 实例也不会被销毁?

public class HolderFragment extends Fragment implements ViewModelStoreOwner {
    private static final String LOG_TAG = "ViewModelStores";

    // 这是什么?请看下面注释分析
    private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final String HOLDER_TAG = "android.arch.lifecycle.state.StateProviderHolderFragment";

    // 这就是我们存放 ViewModel 的 ViewModelStore,就定义在 HolderFragment里
    private ViewModelStore mViewModelStore = new ViewModelStore();

    public HolderFragment() {
        // 划重点啦!!!为什么当 activity 由于屏幕旋转等被系统销毁时,
        // 这个 fragment 实例也不会被销毁?因为设置了 setRetainInstance(true)
        setRetainInstance(true);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 当 Fragment 的 onCreate 方法执行,说明了 Fragment 已经成功添加到了 Activity,
        // sHolderFragmentManager 是 HolderFragmentManager类,它的 holderFragmentCreated()方法
        // 是将该 Fragment 从 mNotCommittedActivityHolders 或 mNotCommittedFragmentHolders 中移除
        // (HolderFragmentManager 的说明,请看下面的注释)
        sHolderFragmentManager.holderFragmentCreated(this);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 当一个设置了 setRetainInstance(true) 的 Fragment 的 onDestroy 方法被调用,
        // 证明它依附的 Activity 已经寿终正寝,所以调用 mViewModelStore.clear(),
        // 前面我们已经说了,这个 clear 方法会调用所有 ViewModel 对象的 onCleared 方法
        // 并且清空它们,我们可以在 ViewModel 的onCleared 方法做一些处理,以免起来不必要的
        // 内存泄漏等问题
        mViewModelStore.clear();
    }

    // 该方法用于给外部调用,返回 ViewModelStore
    @Override
    public ViewModelStore getViewModelStore() {
        return mViewModelStore;
    }

    // 静态方法,没 ViewModelStores.of 方法中被调用
    // 作用:在 activity 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStore
    public static HolderFragment holderFragmentFor(FragmentActivity activity) {
        return sHolderFragmentManager.holderFragmentFor(activity);
    }

    // 静态方法,没 ViewModelStores.of 方法中被调用
    // 作用:在 fragment 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStore
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(Fragment fragment) {
        return sHolderFragmentManager.holderFragmentFor(fragment);
    }

    // 上面的大部分操作都是基于HolderFragmentManager,我们来分析下这个类
    @SuppressWarnings("WeakerAccess")
    static class HolderFragmentManager {

        // 存放还没被系统正式添加到 Activity 中的 HolderFragment
        private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
        private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();

        // 声明定义了一个能够感知 Activity 生命周期的 ActivityLifecycleCallbacks 
        private ActivityLifecycleCallbacks mActivityCallbacks =
                new EmptyActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityDestroyed(Activity activity) {
                        // 当 Activity destroy 的时候,清除 mNotCommittedActivityHolders 中保存
                        // 的对应 HolderFragment。前面我们分析了 HolderFragment 的 onCreate 方法中
                        // 会请一次 mNotCommittedActivityHolders,为什么在这么还要多此一举呢?其实
                        // 并不是多此一举,因为 Fragment 有可能还没创建完,Activity 就夭折了,那这样子
                        // HodlerFragment 的 onCreate 就无法调用,所以在加多一层清理机制,确保能够
                        // 清除掉(不得不感叹,谷歌官方的严谨以及对源码的掌控理解能力)
                        HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
                        }
                    }
                };

        private boolean mActivityCallbacksIsAdded = false;

        private FragmentLifecycleCallbacks mParentDestroyedCallback =
                new FragmentLifecycleCallbacks() {
                    @Override
                    public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
                        // 与 mActivityCallbacks 的分析同理
                        super.onFragmentDestroyed(fm, parentFragment);
                        HolderFragment fragment = mNotCommittedFragmentHolders.remove(
                                parentFragment);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
                        }
                    }
                };

        // HolderFragment 的 onCreate 生命周期被回调,就会调用这个方法,清除
        // mNotCommittedActivityHolders 或者 mNotCommittedFragmentHolders 中
        // 的引用的 HolderFragment
        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);
            // 我们新添加 add 的 Fragment 并不会马上就执行添加完(也就是说,这个方法执行完成后,马上再
            // 调用一次,上面的 findHolderFragment 会返回 null。但是这没有关系,因为接下来我们还可
            // 从 mNotCommittedActivityHolders 获取到对应的实例),所以我们这里先把他放在
            // mNotCommittedActivityHolders 中。Not Committed 表示 fragment 的 commit 还没有完成
            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;
        }
    }
}复制代码

通过上面的注释,我们已经详细地对 HolderFragment 这个核心类做了分析,总结一下:

  • HolderFragment 通过设置 setRetainInstance(true) ,使得自身能够不受到屏幕旋转等configuration changes影响而存活,直到依附的 Activity 正常结束。
  • 因为 HolderFragment 的生命周期, ViewModelStore 对象保存在 HolderFragment 中,而 ViewModel 又存储在 ViewModelStore 中,这就是为什么我们说 ViewModel 类能够让数据在屏幕旋转等配置信息改变导致UI重建的情况下不被销毁。

总结

ViewModel 的分析就到此为止了,我们主要解决了两个问题:

  • ViewModel是怎样创建的?

通过调用 ViewModelProviders.of(this).get(XxxViewModel.class) 或者 ViewModelProviders.of(this,  mFactory).get(XxxViewModel.class) 返回 ViewModel 。最终 ViewModel 实际上是由 Factory 创建,当我们不传 Factory 参数时,系统默认使用 AndroidViewModelFactory 作为 Factory ,通过反射生成 ViewModel 实例对象返回。

  • ViewModel以及存储在其中的数据是怎样在屏幕旋转下依然保留在内存中的?

GC垃圾回收机制不会回收被强引用的对象。在开发过程中,我们需要存储的数据被 ViewModel 引用, ViewModelViewModelStore 引用,而 ViewModelStore 又被 HolderFragment 引用,于是就形成了一条引用链: HolderFragment -> ViewModelStore -> ViewModel ->我们想要存储的数据(最佳实践是 LiveData )。通过上面 HolderFragment 的分析,我们知道 HodlerFragment 在创建时,设置了 setRetainInstance(true) ,因此它使得自身能够不受到屏幕旋转等configuration changes影响而存活,直到依附的 Activity 正常结束。

最后,附上一副时序图供诸位朋友们帮助理解记忆:

Android 官方架构组件(三)——ViewModel


以上所述就是小编给大家介绍的《Android 官方架构组件(三)——ViewModel》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Beginning PHP and MySQL 5

Beginning PHP and MySQL 5

W. Jason Gilmore / Apress / 2006-01-23 / USD 44.99

Beginning PHP and MySQL 5: From Novice to Professional, Second Edition offers comprehensive information about two of the most prominent open source technologies on the planet: the PHP scripting langua......一起来看看 《Beginning PHP and MySQL 5》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具