ViewModel 的设计与常用用法。

ViewModel 用法 原理
ViewModel 这个主要就是提供我们存储东西的类,跟随生命周期去做释放等
ViewModelStore 提供 ViewModel 的存储,一个 Store 支持按照 Key 存多个 ViewModel
ViewModelStoreOwner 该 Store 所属于的角色,例如 是 Fragment 还是 Activty
ViewModelProvider 需要传入对应的 Store
Factory 创建一个 ViewModel
NonConfigurationInstance 对 ViewModelStore 的存储与恢复,最终在系统的 Activity 以及 ActivityThread 里面驱动保存和恢复的,这里需要看系统源码。

流程分析:

// 入口,我们使用的时候怎么获取到一个 ViewModel
    private val viewModel: GrowthViewModel by lazy { ViewModelProvider(this).get(GrowthViewModel::class.java) }
// 这里是 kotlin 写法,使用 lazy 代理方式去加载,里面传入的是一个 ViewModelStoreOwener */

// get 方法,首先判断 store 里面有就直接返回,否则使用 factory 创建并且放到 store 里面
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        // 这里如果是 Fragment 共用 Activity 的 ViewModel 这里的 Key 是一样的,所以复用就保证了 ViewModel 的一致性,因此,在 Fragment 里面彼此之间传递数据用这种方式更好。
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            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);
        }
        // 这里就是存到 store 的 map 里面,以 生成的 String 为 key viewModel 作为 value
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }

// FragmentActivity 的 getViewModelStore,调用到父类的 方法里
    public ViewModelStore getViewModelStore() {
        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 (mViewModelStore == null) {
            // 从 NonConfigurationInstances 里面取
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

// 陷入到 Activity 里面
    public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }   

// attach 里面拿到这个
mLastNonConfigurationInstances = lastNonConfigurationInstances;

// 经过上次的追踪,是系统帮我们存起来的这个 NonConfiguration 里面的,onAttach 的时候放入就置空,为了有效性
    static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }


总结

ViewModel 怎样帮我们做到了数据分离呢,主要就是因为系统给我们提供了存储和取用,方便了我们生命周期的管理,ViewModel 并没有生命感知能力,但是却可以保证很快的把这个 Model 给我们,那么我们无论从中获取 LiveData 还是获取一些自定义的数据,例如普通数据,Flow 等等,都是可以的。 ViewModel 怎样保证了数据的单向流动,就是我们 UI 只是依赖他们,但是他们并不会持用我们 UI 任何东西,这样能避免 UI 上的依赖和互相引用的问题,这样不会在 UI 哪里去让请求网络或者 IO 的时候匿名内部类去持有 UI 承载,另外,还有一个目的就是做到职责分离,在 ViewModel 里面通过 Repository 层或者自己去请求和处理数据,那么这会的触发和处理都下放到 ViewModel 及其后面的一系列流程中了,这样就能做到 UI 和 数据 的分离。我们的设计上也应该遵循这些原则,既然谷歌给提供了这些便利的组件,那我们就直接用,在设计别的方面的时候我们要借鉴。 这里如果配合 Kotlin 的委托 lazy 等方式,直接就可以做到依赖注入的类似效果了。