ViewModel相关详解

本文已参与「新人创作礼」活动,一起开启创作之路。


一、ViewModel的基础概念

ViewModel主要用于存放页面相关数据,其生命周期与Activity不同,只有当Activity退出时,才会一起被销毁。
当Activity受配置更改的影响而重建时,ViewModel中的数据并不会丢失,使得页面的重建更为简单快速。
同一Activity中的Fragment可以共享ViewModel中的数据,通信方便。

viewmodel生命周期:

ViewModel相关详解

二、ViewModel实际运用

​​1、创建自己的ViewModel,继承ViewModel类即可,在内部丰富属性和方法,用于存储和操作数据

ViewModel相关详解
ViewModel相关详解​​

2、简单实现ViewModel,因为需要和Activity绑定,所以不可直接通过构造函数实现,需要通过ViewModelProvider来实现。

ViewModel相关详解
ViewModel相关详解​​

3、由于不能直接通过构造函数实例化ViewModel,故不能直接通过带参构造函数对ViewModel中数据进行初始化,此功能可通过自定义factory实现ViewModel相关详解​​

ViewModel相关详解

ViewModel相关详解

三、详解ViewModel与Factory

查看ViewModelProvider的源码可以知道,其内部重载有三个构造函数,前者为ViewModel的存储器,后者为Factory。其中,前者我们传入的是Activity,所以这里的owner其实是Activity;另外,如果没有指定Factory,则会在owner中查找是否含有Factory,若没有,则指定一个NewInstanceFactory,也就是说,如果我们只是简单是传入Activity或者Fragment,则会指定为NewInstanceFactory

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ?((HasDefaultViewModelProviderFactory)owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }
    public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }
    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

看一下NewInstanceFactory里面是什么东西。其内部真正有用的是在create方法中,通过反射实例化一个class的对象

    public static class NewInstanceFactory implements Factory {
        private static NewInstanceFactory sInstance;
        @NonNull
        static NewInstanceFactory getInstance() {
            if (sInstance == null) {
                sInstance = new NewInstanceFactory();
            }
            return sInstance;
        }
        @SuppressWarnings("ClassNewInstance")
        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            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);
            }
        }
    }

到此,能获得的信息有两个:

其一是将传入的Activity作为ViewModel的存储器,其二是指定了一个Factory,用于初始化。那这两个功能在哪实现的呢,那就要看get里面的代码了,ViewModel就是通过,将自身的class,传入ViewModelProVider的get方法获得的嘛

    private static final String DEFAULT_KEY =
            "androidx.lifecycle.ViewModelProvider.DefaultKey";
    @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)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
        } else {
            viewModel = mFactory.create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

可以看到,我们传入Class的那个get方法,获取到Class的名字之后,通过与DEFAULT_KEY拼成了一个key,和Class一起传入了自己的重载。重载后的get方法,逻辑如下:

在mViewModelStore中通过key获取VIewModel,获取到的这个ViewModel如果与传入get中的ViewModel类型相同,则return此ViewModel,否则,则判断Factory的类型是否为KeyedFactory(这个类也是ViewModelProVider中的一个内部类,其中有一个带有key和class两个参数的抽象方法create),因为前面过来的是NewInstanceFactory是继承自Factory类,所以直接执行create方法,即执行了上文中提到的反射获得对象,然后将这个key和ViewModel存入ViewModelStore中(这个ViewModelStore是在Activity中获取到的,也就是说,将这个ViewModel存入了Activity)。

由此我们可以知道:

1、Activity中有一个ViewModelStore(在祖宗类ComponentActivity中声明的属性),用于存储此Activity中所有的ViewModel,并且以他们的名字为Key存储,同类型的ViewModel只能储存一个,以此保证了ViewModel的一致行,数据安全性。

2、如果不指定Factory,则会默认执行最简单的Factory进行ViewModel的实例化,无法对ViewModel实例化的时候进行数据的初始化设置,想要实现此功能,可以自己声明指定一个Factory,重写内部的create方法则可。自定义的Factory可以继承ViewModelProvider.Factory类或者ViewModelProvider.KeyedFactory类都可,两者内部方法有细微差别,此处不做深入讨论。