Android Jetpack——ViewModel源码解析

一、前言

之前我们已经介绍了ViewModel的意义和使用方式。我们知道,在一个Activity创建ViewModel对象的时候,当由于系统配置变化导致Activity销毁重建的时候,ViewModel对象并不会被有任何影响,由此可知在ViewModel中存储的数据,也不会发生变化。这对于我们开发者来说是很方便的。
我们知道Activity的onSaveInstanceState和onRestoreInstanceState也可以做到这一点,但是我们知道onSaveInstanceState和onRestoreInstanceState是通过把数据序列化到内存,再从内存中反序列化出来。通常是针对一些可以序列化和反序列化的小量数据,如果是大量的数据,或者没有序列化的,则不行了。
了解了ViewModel的强大的功能之后,我们先用一张图来描述ViewModel的生命周期的变化:


image.png

从图中我们可以看到,只有Activity真正的销毁的时候,ViewModel才会被清除掉,对应图中的onCleared方法。

二、源码解析

下面我们来分析ViewModel的源码。我们先看下ViewModel对象的创建方式:

   viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

代码很简单,首先调用ViewModelProviders的of方法创建ViewModelProvider对象。其实从类的命名上看就很容易理解,ViewModelProviders和ViewModelProvider只差一个s,ViewModelProviders是一个集合,ViewModelProvider是集合中的一个对象,of(this)则是通过传入当前Activitiy的实例作为key,获取ViewModelProviders中ViewModelProvider对象。是不是这个意思呢?我们继续分析:

 @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment) {
        return of(fragment, null);
    }

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

   @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
        Application application = checkApplication(checkActivity(fragment));
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(ViewModelStores.of(fragment), factory);
    }

  @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
        Application application = checkApplication(activity);
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }

我们看到of方法中有四个重载的方法,她们的区别就是传入的this是Activity还是Fragment,还有就是,是否有Factory 对象。如果没有Factory对象,则创建默认的Factory。然后通过以下方式返回ViewModelProvider 对象

 return new ViewModelProvider(ViewModelStores.of(fragment), factory);

我们看下ViewModelProvider的构造函数:

  public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        this.mViewModelStore = store;
    }

ViewModelStore 和Factory 对象顾名思义ViewModelStore 是用来存储ViewModel的Factory 是用来创建ViewModel的。通过ViewModelStores.of(fragment)创建获取ViewModelStore实例,接着我们看下ViewModelStores.of(fragment)的实现

  @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull Fragment fragment) {
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        return holderFragmentFor(fragment).getViewModelStore();
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(Fragment fragment) {
        return sHolderFragmentManager.holderFragmentFor(fragment);
    }

 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 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;
        }

我们看到获取ViewModelStore实例最终调用了holderFragmentFor方法获取HolderFragment 实例holder ,而HolderFragment 继承了ViewModelStoreOwner。在holderFragmentFor方法中首先根据activity作为key,判断holder 是否存在。如果存在里,就直接返回holder。

  HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedActivityHolders.get(activity);
            if (holder != null) {
                return holder;
            }

如果不存在则创建新的holder返回,并把holde存到mNotCommittedActivityHolders这个Map中,以Activity作为key。

 if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
                activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
            }
            holder = createHolderFragment(fm);
            mNotCommittedActivityHolders.put(activity, holder);
            return holder;

这样一来我们可以知道,只要HolderFragment 没有被销毁,mNotCommittedActivityHolders这个Map就会存在,那么存放在Map中的ViewModelStoreOwner holder就存在。

return holderFragmentFor(fragment).getViewModelStore();

然后通过getViewModelStore()方法可以得到ViewModelStore对象。
接着我们看下get方法

  viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

    @NonNull
    @MainThread
    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;
    }

我们很容易知道,首先从Map中根据key获取ViewModel 对象

ViewModel viewModel = mViewModelStore.get(key);

如果viewModel 不为空,则返回,否则创建一个ViewModel对象,存放在Map中。

  ViewModel oldViewModel = mMap.put(key, viewModel);

并且我们知道存放ViewModel的Key和Activity或者Fragment是对应起来的。所以说当Activity重建的时候,只要mViewModelStore对象还是原来的对象,那么ViewModel对象就不会变,而且我们在上面分析知道mViewModelStore又存放到了HolderFragment中,也是存放到了Map中,所以只要HolderFragment没有被销毁,mViewModelStore就不会被销毁。mViewModelStore没有被销毁,ViewModel就没有被销毁。ViewModel没有被销毁,ViewModel里面的数据就没有被销毁。因此得出了我们的结论。在Activity销毁重建的时候,ViewModel里的数据是不会丢失的。

三、小结

我们对ViewModel的源码做一个小结:
1、创建HolderFragment,并在HolderFragment中初始化Map<Activity, HolderFragment> mNotCommittedActivityHolders 用于存放 HolderFragment holder。
2、从HolderFragment 获取ViewModelStore mViewModelStore
3、ViewModelStore 用于存放ViewModel对象,创建ViewModelProvider实例,传入ViewModelStore 对象,对ViewModelProvider中的ViewModelStore进行初始化。
4、通过 mViewModelStore.put(key, viewModel);获取ViewModel实例。
其实ViewModel最核心的部分就是HolderFragment 中存放了ViewModelStore 。因为Activity在销毁重建的时候HolderFragment 并不收到影响,所以ViewModelStore 不会丢失。从而下面的一系列得到ViewModel对象不会销毁。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容