ViewModel原理解析

370 阅读5分钟

ViewModel原理解析

ViewModel的出现是为了解决什么问题?

为了代码的可读性和可维护性,我们在设计程序架构时,会以各种模式来进行设计,以实现程序的高内聚,低耦合,进行业务分层。如MVC、MVP、MVVM。

最初的MVC模式,model/view/contorle,model数据层、view界面层、control控制层。model为数据层用来处理数据,view界面层用来显示view,这里的view包括activity/fragment/view等,里面会编写界面逻辑和部分业务逻辑。control控制层主要是业务逻辑代码。

为了更好的管理生命周期,MVP模式应运而生,MVP面向接口编程,分为model/view/persenter,view和persenter之间通过接口传递数据、不直接持有对方的实例对象,减少了内存溢出,同时能更好的管理生命周期。但弊端是接口数量爆炸,后期维护成本高。

这个时候ViewModel出现了,ViewModel可以帮你管理生命周期,并且在屏幕旋转等造成的Activity/fragment生命周期变化,ViewModel的实例也不会销毁重建、直到activity/fragment销毁,viewModel才会销毁。MVVM模式就是model/view/viewModel,view/viewModel使得程序符合关注点分离原则,view只负责显示数据、viewModel只用来处理业务逻辑。

ViewModel的基本使用

viewMoel生命周期图

首先来看怎么使用ViewModel

1.创建继承自ViewModel的子类

class MainFragmentViewModel : ViewModel() {}

2.在Activity/fragment中获取ViewModel实例对象,这里以fragment为例

    val viewMode: MainFragmentViewModel = ViewModelProvider(this).get(MainFragmentViewModel::class.java)

3.接下来就可以通过viewModel对象调用其中的方法了。

ViewModel源码解析

通过ViewModel的基本使用可以看到,获取ViewModel的实例对象需要通过构造方法创建ViewModelProvider实例,并调用get方法。

1.首先看ViewModelProvider的构造方法

    /**
    *Creates ViewModelProvider. This will create ViewModels and retain
    *them in a store of the given ViewModelStoreOwner.
    *This method will use the default factory if the owner implements
    *HasDefaultViewModelProviderFactory. Otherwise, a NewInstanceFactory
    *will be used.
    **/
    public constructor(
        owner: ViewModelStoreOwner
    ) : this(owner.viewModelStore, defaultFactory(owner))

通过构造方法可以看出,需要一个ViewModelStoreOwner类型的参数,而Activity/fragment实现了ViewMoelStoreOwner接口,所以activity/fragment对象可以作为参数入参

接下来调用了this方法,即调用了该类构造方法的重载方法

public open class ViewModelProvider(
    private val store: ViewModelStore,
    private val factory: Factory
) {}

第二个参数需要一个Factory类型的参数,这个参数由defaultFactory方法提供,下面看一下这个方法

        public companion object {
            internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
                if (owner is HasDefaultViewModelProviderFactory)
                    owner.defaultViewModelProviderFactory else instance

可以看到判断owner是否继承或实现了HasDefaultViewModelProviderFactory接口,如果实现了,就使用其自己的defauleViewModelProviderFactory。

这里activity/fragment已经实现了HasDefaultViewModelProviderFactory接口,那么看一下activity/fragment自己实现的defaultViewModelProviderFactory,其实就是创建了一个SavedStateViewModelFactory。

这里看一下activiy的实现

    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mDefaultFactory == null) {
            mDefaultFactory = new SavedStateViewModelFactory(
                    getApplication(),
                    this,
                    getIntent() != null ? getIntent().getExtras() : null);
        }
        return mDefaultFactory;
    }

代码如上,如果mDefaultFactory为null,就通过new的方式构造SavedStateViewModelFactory对象返回,不为null,就直接返回。

这里先看一下SavedStateViewModelFactory类的构造方法

    public SavedStateViewModelFactory(@Nullable Application application,
            @NonNull SavedStateRegistryOwner owner,
            @Nullable Bundle defaultArgs) {
        mSavedStateRegistry = owner.getSavedStateRegistry();
        mLifecycle = owner.getLifecycle();
        mDefaultArgs = defaultArgs;
        mApplication = application;
        // 如果application不为null 获取factory
        mFactory = application != null
                ? ViewModelProvider.AndroidViewModelFactory.getInstance(application)
                : ViewModelProvider.NewInstanceFactory.getInstance();
    }

注意上面的注释,如果application不为null,会获取factory,这application在activity/fragment中肯定是不为null的,所以会调用AndroidViewModelFactory.getInstance方法获取factory对象

接下来就是调用ViewModelProvider类中的get方法

    public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
        // 根据key,先从viewModelStore中获取viewModel
        var viewModel = store[key]
        // 这里判断viewModel是否为null
        if (modelClass.isInstance(viewModel)) {
            (factory as? OnRequeryFactory)?.onRequery(viewModel)
            // 不为null viewModel类型转换为需要的类型
            return viewModel as T
        } else {
            @Suppress("ControlFlowWithEmptyBody")
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        // 这里viewModel为null 需要从factory中创建
        viewModel = if (factory is KeyedFactory) {
            factory.create(key, modelClass)
        } else {
            factory.create(modelClass)
        }
        // 保存到viewModelStore
        store.put(key, viewModel)
        return viewModel
    }

从上面注释可以看出,先从viewModelStore中根据key获取viewModel对象,如果viewModel不为null,就类型转换为我们需要的viewModel类型,如果为null,就通过factory创建,这里的factory就是SavedStateViewModelFactory

public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor<T> constructor;
        if (isAndroidViewModel && mApplication != null) {
            // 查找匹配的构造
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }
        // doesn't need SavedStateHandle
        // 不需要SavedStateHandle
        if (constructor == null) {
            return mFactory.create(modelClass);
        }

        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            if (isAndroidViewModel && mApplication != null) {
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
            return viewmodel;
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to access " + modelClass, e);
        } catch (InstantiationException e) {
            throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("An exception happened in constructor of "
                    + modelClass, e.getCause());
        }
    }

上面代码可以知道,当构造viewModel不需要SaveStateHandle参数时,直接通过mFactory.create方法创建viewModel,这里的mFactory就是AndroidViewModelFactory

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

以上代码得知,最后通过反射创建了ViewModel的实例对象。

最后,viewModel何时销毁呢,看ComponeActivity的构造方法

        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // Clear out the available context
                    mContextAwareHelper.clearAvailableContext();
                    // And clear the ViewModelStore
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });

当destory时,调用viewModelStore的clear方法

    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }

总结

viewModel对象在不指定viewModelFactory时由AndroidViewModelFactory通过反射的方式创建,并保存在viewModelStore中,在需要时,从viewModelStore中获取,在activity/fragment销毁时,销毁