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

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

ViewModel生命周期

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

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

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

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

ViewModel原理分析

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

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

  • ViewModel、ViewModelProvider、HolderFragment、ViewModelStore

!](http://upload-images.jianshu.io/upload_images/16647779-b1d8c84e7ffde685?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

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

(在这里默认大家已经知道了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 的 create 方法生成 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方法遍历调用所有ViewModel的onCleared方法并且清空map。

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

HolderFragment

前面我们分析ViewModelStores.of()方法的时候,提到过调用静态方法holderFragmentFor()方法能够返回一个继承了ViewModelStoreOwner的HolderFragment实例,现在我们就来看看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引用,ViewModel被ViewModelStore引用,而ViewModelStore又被HolderFragment引用,于是就形成了一条引用链:HolderFragment->ViewModelStore->ViewModel->我们想要存储的数据(最佳实践是LiveData)。通过上面HolderFragment的分析,我们知道HodlerFragment在创建时,设置了setRetainInstance(true),因此它使得自身能够不受到屏幕旋转等configuration changes影响而存活,直到依附的Activity正常结束。

最后

喜欢的话可以关注一下哦,会每天更新android相关的文章。

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

推荐阅读更多精彩内容