Android Architecture Component之ViewModel解析

作者 : 开心源码 本文共9993个字,预计阅读时间需要25分钟 发布时间: 2022-05-11 共54人阅读

博文出处:Android Architecture Component之ViewModel解析,欢迎大家关注我的博客,谢谢!

Header

之前给大家分析过了 LiveData ,今天就来看看 ViewModel 。

ViewModel 的作使用就相当于 MVP 中的 Presenter ,是使用来衔接 Model 和 View 的。通常把少量与 View 无关的业务逻辑写在 ViewModel 里面。ViewModel 内部创立出 LiveData 对象,利使用 LiveData 对象来传递数据给 View 。

ViewModel 相对于 Presenter 而言,有以下几个好处:

  1. ViewModel 并不直接持有 View ,所以在 ViewModel 销毁时不需要像 Presenter 一样地去手动解除 View 的绑定,也就不会造成持有 View 导致的内存泄漏;
  2. 比方 Activity 配置改变的情况下,ViewModel 会保存不会丢失数据;
  3. ViewModel 能做到在同一个 Activity 的情况下,多个 Fragment 共享数据;

下面是官方给出的 ViewModel 生命周期图,大家随便感受一下:

[图片上传失败…(image-e38635-1531153914120)]

那么就开始进入正题吧。

本次解析的 ViewModel 源码基于 android.arch.lifecycle:extensions:1.1.1

ViewModel

先来看看 ViewModel 是怎样被创立出来的:

    XXXViewModel xxxViewModel = ViewModelProviders.of(activity).get(XXXViewModel.class)

能看到 ViewModel 并不是简单地 new 出来的,这其中的逻辑要需要我们一步一步慢慢揭开。

那么 ViewModel 是怎么被定义的呢?

ViewModel

public abstract class ViewModel {    /**     * This method will be called when this ViewModel is no longer used and will be destroyed.     * <p>     * It is useful when ViewModel observes some data and you need to clear this subscription to     * prevent a leak of this ViewModel.     */    @SuppressWarnings("WeakerAccess")    protected void onCleared() {    }}

原来 ViewModel 是个笼统类,里面只有一个 onCleared() 方法。 onCleared() 会在 ViewModel 被销毁时回调,所以能在 onCleared() 里面做少量释放资源、清除内存的操作。

另外,ViewModel 还有一个子类: AndroidViewModel 。AndroidViewModel 在 ViewModel 的基础上内部包含了 application 。

ViewModelProviders

我们就来抽丝剥茧了,先从 ViewModelProviders 入手。创立 ViewModel 时在 ViewModelProviders 中调使用了 of 方法。

of

    @NonNull    @MainThread    public static ViewModelProvider of(@NonNull FragmentActivity activity) {        return of(activity, null);    }    @NonNull    @MainThread    public static ViewModelProvider of(@NonNull Fragment fragment) {        return of(fragment, 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 方法能分为两个入口,分别对应着 Fragment 和 Activity 。这也说明了 ViewModel 的作使用域其实是分为两个维度的。但是这两个方法内部的代码很像,逻辑基本都是:

  1. 先去获取 application ;
  2. 创立 factory ;
  3. 创立 ViewModelProvider ,ViewModelProvider 顾名思义就是提供 ViewModel 的;

第一步就不使用说了,直接进入第二步吧。

Factory

Factory 是什么东东呢,说白了就是 ViewModel 的制造工厂。所有的 ViewModel 都是由 Factory 来创立出来的。

    public interface Factory {        /**         * Creates a new instance of the given {@code Class}.         * <p>         *         * @param modelClass a {@code Class} whose instance is requested         * @param <T>        The type parameter for the ViewModel.         * @return a newly created ViewModel         */        @NonNull        <T extends ViewModel> T create(@NonNull Class<T> modelClass);    }

Factory 是个接口,里面定义了 create 方法来创立 ViewModel 。来看看它的实现类 NewInstanceFactory 。

NewInstanceFactory

    /**     * Simple factory, which calls empty constructor on the give class.     */    public static class NewInstanceFactory implements Factory {        @SuppressWarnings("ClassNewInstance")        @NonNull        @Override        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {            //noinspection TryWithIdenticalCatches            try {                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);            }        }    }

其实没啥好说的,就是利使用反射来创立实例了,是一个很简单的实现类。NewInstanceFactory 其实是创立普通 ViewModel 的工厂,而假如想创立 AndroidViewModel 的话,工厂就要选择 AndroidViewModelFactory 了。

AndroidViewModelFactory

    /**     * {@link Factory} which may create {@link AndroidViewModel} and     * {@link ViewModel}, which have an empty constructor.     */    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {        private static AndroidViewModelFactory sInstance;        /**         * Retrieve a singleton instance of AndroidViewModelFactory.         *         * @param application an application to pass in {@link AndroidViewModel}         * @return A valid {@link AndroidViewModelFactory}         */        @NonNull        public static AndroidViewModelFactory getInstance(@NonNull Application application) {            if (sInstance == null) {                sInstance = new AndroidViewModelFactory(application);            }            return sInstance;        }        private Application mApplication;        /**         * Creates a {@code AndroidViewModelFactory}         *         * @param application an application to pass in {@link AndroidViewModel}         */        public AndroidViewModelFactory(@NonNull Application application) {            mApplication = application;        }        @NonNull        @Override        public <T extends ViewModel> T create(@NonNull Class<T> 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 的 create 方法中,对创立 ViewModel 的方案做了兼容,所以 AndroidViewModelFactory 是同时适使用于创立 ViewModel 和 AndroidViewModel 的。并且 AndroidViewModelFactory 是单例工厂,防止屡次创立白费内存。

额外补充一点,在 ViewModelProviders 中有一个内部类 DefaultFactory ,现在已经被打上废弃的标签了,能猜出这个 DefaultFactory 应该是早期版本的默认工厂类,现在已经被 AndroidViewModelFactory 代替了。

ViewModelStores

到这里 Factory 就有了,那么就重点来看看 ViewModelStores.of(activity) 这段代码了。ViewModelStores 是根据作使用域使用来提供 ViewModelStore 的,而 ViewModelStore 的作使用就是存储 ViewModel ,内部是利使用 key/value 将 ViewModel 保存在 HashMap 中,方便读写,这里就不展现 ViewModelStore 的源码了,大家能把 ViewModelStore 当作 HashMap 就行。

    /**     * Factory methods for {@link ViewModelStore} class.     */    @SuppressWarnings("WeakerAccess")    public class ViewModelStores {            private ViewModelStores() {        }            /**         * Returns the {@link ViewModelStore} of the given activity.         *         * @param activity an activity whose {@code ViewModelStore} is requested         * @return a {@code ViewModelStore}         */        @NonNull        @MainThread        public static ViewModelStore of(@NonNull FragmentActivity activity) {            if (activity instanceof ViewModelStoreOwner) {                return ((ViewModelStoreOwner) activity).getViewModelStore();            }            return holderFragmentFor(activity).getViewModelStore();        }            /**         * Returns the {@link ViewModelStore} of the given fragment.         *         * @param fragment a fragment whose {@code ViewModelStore} is requested         * @return a {@code ViewModelStore}         */        @NonNull        @MainThread        public static ViewModelStore of(@NonNull Fragment fragment) {            if (fragment instanceof ViewModelStoreOwner) {                return ((ViewModelStoreOwner) fragment).getViewModelStore();            }            return holderFragmentFor(fragment).getViewModelStore();        }    }

根据 ViewModelProviders 的思路,ViewModelStores 也是分为了两个方法,对应着 Fragment 和 Activity 。

  1. 假如 Activity 和 Fragment 实现了 ViewModelStoreOwner 的接口,那么直接返回内部的 ViewModelStore 就行了;
  2. 假如是之前老早版本的 Activity 或者者 Fragment ,那么它们一定是没有实现 ViewModelStoreOwner 接口的,那该怎样办呢?很简单,新创立一个 Fragment 来关联 ViewModelStoreOwner 就好了啊!

所以就有了 holderFragmentFor(activity) 和 holderFragmentFor(fragment) 这段了。

HolderFragment

HolderFragment 实现了 ViewModelStoreOwner 接口,所以 HolderFragment 的作使用就是代替了那些之前没有实现 ViewModelStoreOwner 接口的 Activity/Fragment 。这样,Activity/Fragment 也间接地拥有了 ViewModelStore 。

HolderFragment 的代码我们就只看 holderFragmentFor(activity) 这一段吧,holderFragmentFor(fragment) 也是相似的。

    /**     * @hide     */    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)    public static HolderFragment holderFragmentFor(FragmentActivity activity) {        return sHolderFragmentManager.holderFragmentFor(activity);    }    static class HolderFragmentManager {        ...            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;        }    } 

其实就是把 HolderFragment 增加进 Activity 里面,这样 HolderFragment 就和 Activity 的生命周期关联在一起了。实际上获取的就是 HolderFragment 里面的 ViewModelStore 。每个 Activity 里面只有一个 HolderFragment 。

Fragment 也是同理,利使用 getChildFragmentManager() 来往里增加 HolderFragment 。这里就不讲了,有兴趣的同学能自己回去看看源码。

至此,使用来创立 ViewModelProvider 的两个入参 ViewModelStore 和 Factory 都讲完了。

ViewModelProvider

创立出 ViewModelProvider 后,最后一步就是调使用它的 get 方法返回 ViewModel 了。

    @NonNull    @MainThread    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {        String canonicalName = modelClass.getCanonicalName();        if (canonicalName == null) {            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");        }        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);    }    @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;    }

get 方法很 easy ,就是利使用 class 的 canonicalName 生成一个唯一的 key ,而后利使用 key 去 mViewModelStore 中获取。假如有值就返回,否则就利使用 factory 创立新的 ViewModel ,而后保存到 mViewModelStore 中并返回。

整个 ViewModel 的源码流程基本上就讲完了,其实并不复杂。回去多多体会,总可以明白其中的奥秘。

下面,额外给大家补充几个小点,加个鸡腿。

Tip

ViewModel的onCleared什么时候回调

之前说过,ViewModel 是保存在 ViewModelStore 里面的,所以 ViewModel 的销毁肯定是在 ViewModelStore 里面操作的。

ViewModelStore

    /**     *  Clears internal storage and notifies ViewModels that they are no longer used.     */    public final void clear() {        for (ViewModel vm : mMap.values()) {            vm.onCleared();        }        mMap.clear();    }

能看到 ViewModelStore 的 clear() 方法内部调使用 ViewModel 的 onCleared() 方法。那么哪里调使用了 ViewModelStore 的 clear() 方法呢?

Fragment

    /**     * Called when the fragment is no longer in use.  This is called     * after {@link #onStop()} and before {@link #onDetach()}.     */    @CallSuper    public void onDestroy() {        mCalled = true;        // Use mStateSaved instead of isStateSaved() since we're past onStop()        if (mViewModelStore != null && !mHost.mFragmentManager.mStateSaved) {            mViewModelStore.clear();        }    }

能从代码上看到,Fragment 的销毁操作调使用是在 onDestroy() 中。

另外,假如状态保存标记值 mStateSaved 为 true 的情况下,是不会去清理 ViewModel 的,这也是为什么上面中讲的配置改变的情况下,数据得以保持住的起因。

FragmentActivity

    /**     * Destroy all fragments.     */    @Override    protected void onDestroy() {        super.onDestroy();        doReallyStop(false);        if (mViewModelStore != null && !mRetaining) {            mViewModelStore.clear();        }        mFragments.dispatchDestroy();    }

同理, Activity 的销毁操作也是在 onDestroy() 完成的。

Footer

终于把 LiveData 和 ViewModel 都分析了一遍,现在还差一个 Lifecycle 。

那么等有时间再写吧,bye bye!

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Android Architecture Component之ViewModel解析

发表回复