ViewModel

如何使用

1.在Activity中创建使用ViewModel:

/**转入Activity就行*/
        GirlsViewModel girlsViewModel =
        ViewModelProviders.of(ActivityGirls.this).get(GirlsViewModel.class);

2.在Fragment中创建使用ViewModel:

/**转入Fragment就行*/
       GirlsViewModel girlsViewModel =
       ViewModelProviders.of(FragmentGirls.this).get(GirlsViewModel.class);

3.在任意地方创建使用ViewModel:

/**将context强转成FragmentActivity就行*/
      GirlsViewModel girlsViewModel =
      ViewModelProviders.of((FragmentActivity) context).get(GirlsViewModel.class);

ViewModel 的存在是依赖 Activity 或者 Fragment 的,不管你在什么地方获取 ViewModel ,只要你用的是相同的 Activity 或者 Fragment ,那么获取到的 ViewModel 将是同一个 (前提是 key 值是一样的),所以 ViewModel 也具有数据共享的作用!

一、ViewModel是怎么创建的?

上面创建 ViewModel 链式调用分解为下面两步:

/*****第一步:根据Activity或者Fragment获得ViewModelProvider****/
        ViewModelProvider viewModelProvider = ViewModelProviders.of(ActivityGirls.this);

        /*****第二步:使用ViewModelProvider反射创建需要的ViewModel****/
        GirlsViewModel girlsViewModel = viewModelProvider.get(GirlsViewModel.class);

先看第一步获得的源代码:

public static ViewModelProvider of(@NonNull FragmentActivity activity) {

        /**********获得AndroidViewModelFactory ( 内部是单例的 )*******/
        ViewModelProvider.AndroidViewModelFactory factory =
                ViewModelProvider.AndroidViewModelFactory.getInstance(
                        checkApplication(activity));

        /*****创建一个ViewModelProvider( 传入的两个参数是重点 )*****/
        return new ViewModelProvider(ViewModelStores.of(activity), factory);

    }

上面的两步其实很关键了,获得AndroidViewModelFactory , AndroidViewModelFactory 其实是 ViewModelProvider 的静态内部类,看调用方式就知道是一个单例的,就是我们的应用只有有一个单例的 AndroidViewModelFactory 存在,看源码:

/*****`AndroidViewModelFactory `其实是`ViewModelProvider`的静态内部类******/
 public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

        private static AndroidViewModelFactory sInstance;

        /********获得AndroidViewModelFactory 单例**********/
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

        private Application mApplication;
        
        /*************其实构造方式是public 的,还是可以new的****************/
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }
        
        /******其实这里就是创建ViewModel的关键地方,根据给出的Class反射创建需要的ViewModel*******/
        @NonNull
        @Override
        public  T create(@NonNull Class 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);
        }
    }

重点我都标注在注释里了,请耐心看一遍。看到这里我知道了一个全局的 AndroidViewModelFactory 工具类,作用就是反射创建我们想要的类 ViewModel ,其实功能简单的!

获得到的单例 AndroidViewModelFactory 是创建 ViewModelProvider 的第二个参数,下面我们看第一个参数。

第一个参数是这样: ViewModelStores.of(activity)
看源码:

ViewModel_第1张图片

3.ViewModelStores静态方法为Activity创建一个ViewModelStore

解释我就放在注释了,大家看下面的注释把:

@MainThread
    public static ViewModelStore of(@NonNull FragmentActivity activity) {
        //如果你的Activity实现了ViewModelStoreOwner接口具备了提供
        //ViewModelStore 的功能就直接获取返回,通常我们的Activity都不会去实现这个功能
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        //系统为你的Activity添加一个具有提供ViewModelStore 的holderFragment
        return holderFragmentFor(activity).getViewModelStore();
    }

其实解析 ViewModelStore 就可以解释ViewModel的存储,解析 holderFragmentFor(activity).getViewModelStore() 就可解释ViewModel为什么可以在Activity配置发生变化的情况下人不销毁,这些我们就在下面去解释。我第一步重点解释创建不关心其他的。

到这里我们要知道:

第一: AndroidViewModelFactory 在正常情况下是全局单例只有一个,只是一个反射创建对象的工具类。

第二: ViewModelProvider 是每次获取创建 ViewModel 的时候都会创建一个新的。

第三: ViewModelStore 是每一个Activity或者Fragment都有一个。

关注 ViewModel 创建:

//viewModelProvider的get方法
 viewModelProvider.get(GirlsViewModel.class);
ViewModel_第2张图片

4.viewModelProvider的get方法

会用 DEFAULT_KEY 和 类名组成一个key值去获取,接着向下看:

ViewModel_第3张图片

5.ViewModel的创建关键方法

代码很简单,流程如下:

(1) 先从 mViewModelStore 中使用key去获取 ViewModel , mViewModelStore 中是使用 HashMap 去存储一个 Activity 或者 FragmentViewModel 的。如果获取到就返回。

(2) 没获取到就使用单例 mFactory 的create方法反射创建 ViewModel ,create方法的代码在上面贴出来了。

(3) 使用Key存入 mViewModelStore 并返回。

到这里 ViewModel 的创建基本就是讲完了,但是可能还是有些懵逼。下面接着看吧。

一句话总结 ViewModel 是怎么被创建的:

创建一个 ViewModelProvider ,使用 ViewModelProvider 内部的全局单例 AndroidViewModelFactory 来反射创建 ViewModel ,并把创建的 ViewModel 存入传入的 ViewModelStore 中!

二、ViewModel是怎么存储的?

存储就是要讲解 ViewModelStore 了。

直接看源代码:

ViewModel_第4张图片

6.ViewModelStore源码

代码就这数的清的几行,就是一个 HashMap 用存储ViewModel。提供 get , put , clear 三个方法。

上面说了
ViewModelStore 是每一个
Activity 或者
ViewModel 都有一个的,当
Activity 或者
Fragment 销毁的时候就会调用
clear

方法了。

ViewModelStore 被谁创建,被谁持有?-------------------> +_+

抢答:被 HolderFragment 创建和持有!

HolderFragment 跟我们的Activity或者Fragment有什么关系?-------------------> +_+

抢答:当我们要给Activity或者Fragment创建ViewModel的时候,系统就会为Activity或者Fragment添加一个 HolderFragmentHolderFragment 中会创建持有一个 ViewModelStore

HolderFragment 怎么创建怎么被添加?-------------------> +_+

7.每次获取ViewModel都会创建一个ViewModelProvider

这一步其实可以分解为下面的的样子:

/**为Activity或者Fragment创建ViewModelStore*/
        ViewModelStore viewModelStore = ViewModelStores.of(activity);

        /**为本次的ViewModel获取创建一个ViewModelProvider*/
        ViewModelProvider viewModelProvider =  new ViewModelProvider(viewModelStore, factory);

完成了上面两步才可以这样: viewModelProvider.get(想要的ViewModel.class);

正是

/**为Activity或者Fragment创建ViewModelStore*/
       ViewModelStore viewModelStore = ViewModelStores.of(activity / fragment);

这步为我们的 activity / fragment 注入了一个 HolderFragment ,创建 HolderFragment 的时候会创建的时候会创建一个ViewModelStore实例,到这里也解释了一下 ViewModelStore被谁创建,被谁持有? 的问题。

上面我有提过 ViewModelStoreOwner 这个接口,其实我们这里说的 HolderFragment 就是实现了这个接口的Fragment。

一句话总结 ViewModel 是怎么被存储的:

这是上面一句话总结 ViewModel 的创建:

ViewModel_第5张图片

8.ViewModel创建一句话总结

这句创建总结其实也说明了 ViewModel 的存储。

进一步解释:

ViewModel 是存储在当前 Activity / FragmentHolderFragment 中的 ViewModelStore 的HashMap中,我们可以 get , put 或者在 Activity / Fragment 销毁的时候 HolderFragment 会跟随销毁,在 HolderFragmentonDestroy 方法中调用 mViewModelStoreclear 方法。

ViewModel_第6张图片

9.HolderFragment伴随销毁时调用自己所有ViewModel的onCleared方法

三、ViewModel为什么可以实现旋转屏幕不销毁?

ViewModel的创建获取方式是: 为 Activity / Fragment 创建一个 ViewModelStore ,获取到 AndroidViewModelFactory 单例,用这个两个数据创建一个 ViewModelProvider ,在创建的 ViewModelProvider 中可以get我们要的ViewModel。

Activity / Fragment 创建一个 ViewModelStore ,就是调用下面的方法:

ViewModel_第7张图片

10.HolderFragment被注入到Activity / Fragment

holderFragmentFor(activity)源码:

ViewModel_第8张图片

11.holderFragmentFor(activity)

ViewModel_第9张图片

12.单例的HolderFragmentManager

holderFragmentFor(activity)方法每一步都有解释,很详细:

HolderFragment holderFragmentFor(FragmentActivity activity) {

            //获取Activity的FragmentManager
            FragmentManager fm = activity.getSupportFragmentManager();

            //通过HOLDER_TAG在FragmentManager中需要HolderFragment
            HolderFragment holder = findHolderFragment(fm);

            //获得的HolderFragment不为空就返回
            if (holder != null) {
                return holder;
            }

            //在Map缓存中获取HolderFragment
            //Activity为key,所以每一个Activity或者Fragment只会有一个HolderFragment
            holder = mNotCommittedActivityHolders.get(activity);

            //不为空就返回
            if (holder != null) {
                return holder;
            }


            //在Application中注册一个所有Activity生命周期回调监听,这里只会注册一次
            //这里注册Activity生命周期监听的目的是在Activity销毁的时候好移除Map中的对应数据
            if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
                activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
            }

            //new HolderFragment()并通过fm添加到Activity并返回
            holder = createHolderFragment(fm);

            //添加到Map缓存
            mNotCommittedActivityHolders.put(activity, holder);

            //返回
            return holder;
        }

createHolderFragment()方法重点关注一下:

ViewModel_第10张图片

12.createHolderFragment

就是创建了一个
HolderFragment ,使用传入的
FragmentManager

添加进去!

这是上面调用的构造方法:

ViewModel_第11张图片

13.HolderFragment

被设置 setRetainInstance(true) 后的 Fragment 添加到 Activity 中去了,会怎么样?

setRetainInstance(boolean) 是 Fragment 中的一个方法。将这个方法设置为true就可以使当前Fragment在Activity重建时存活下来, 如果不设置或者设置为 false, 当前 Fragment 会在 Activity 重建时同样发生重建, 以至于被新建的对象所替代。

在setRetainInstance(boolean)为true的 Fragment (就是 HolderFragment )中放一个专门用于存储 ViewModel 的Map, 这样Map中所有的ViewModel都会幸免于Activity的配置改变导致的重建,让需要创建 ViewModel 的Activity, Fragment都绑定一个这样的Fragment(就是 HolderFragment ), 将ViewModel存放到这个 Fragment 的 Map 中, ViewModel 组件就这样实现了。

实现原理就是巧妙滴借用了Fragment的setRetainInstance(true)属性。关于setRetainInstance更多介绍可以参考: Android应用开发:Fragment的非中断保存setRetaineInstance

我这里可以展示一下setRetainInstance(true)属性对生命周期的影响,在一个Activity中加入一个具有setRetainInstance(true)属性的Fragment:

ViewModel_第12张图片

setRetainInstance(true)属性演示

三秒钟后展示出了我们的Fragment,生命周期如下:

ViewModel_第13张图片

展示生命周期

然后我们点击模拟器的旋转屏幕按钮:

旋转屏幕按钮

生命周期变化:

ViewModel_第14张图片

旋转生命周期

可以看到Activity因为配置改变了,调了 onDestroy 方法,但是我们的 setRetainInstance(true) 属性的 Fragment 没有调用 onDestroy 方法,说明Fragment得以幸存下来了。

退出当前Activity但是不退出应用后的生命周期:

ViewModel_第15张图片

退出Activity后生命周期

这时候Activity和Fragment的
onDestroy

生命周期方法先后被调用了。

在我的 HolderFragmentonDestroy 方法中,会调用 mViewModelStore 中所有 ViewModelonCleared 方法。

四、总结:

关于ViewModel的实现结构图可以参考如下:图片来源 https://blog.csdn.net/zhuzp_blog/article/details/78910535

ViewModel_第16张图片

13.ViewModel的实现结构图

1. ViewModel 以键值对的形式存在Activity或者Fragment的 HolderFragment

ViewModelStore 的HashMap中。

2.一个Activity或者Fragment可以有很多个 ViewModel

3.一个Activity或者Fragment只会有一个 HolderFragment

4.Activity或者Fragment的 HolderFragment 会保存在全局单例的 HolderFragmentManager 的HashMap中,在Activity或者Fragment销毁的时候会移除HashMap中对应的value。

5.因为 ViewModel 是以Activity或者Fragment为存在基础,所以 ViewModel 可以在当前Activity和Fragment中实现数据共享,前提是传入相同的key值。

你可能感兴趣的:(ViewModel)