美文网首页
ViewModel源码阅读笔记

ViewModel源码阅读笔记

作者: 紫鹰 | 来源:发表于2022-07-21 15:23 被阅读0次

    MVVM模式实现了数据和页面的分离。ViewModel的生命周期需要跟随引用他的activity或者fragment。接下来我们就来看看,ViewModel是如何实现生命周期的伴随的。

    先从ViewModel的创建开始看

    XXXViewModel viewModel = new  ViewModelProvider(fragment).get(XXXViewModel.class)
    

    kotlin扩展函数实现的方式最终也是调用ViewModelProvider的方法实现的,具体细节可以看上篇文章介绍,这里不赘述了

    先看下ViewModelProvider的构造方法

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {  
    this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory  
            ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()  
            : NewInstanceFactory.getInstance());  
    }
    

    构造方法需要传入一个ViewModelStoreOwner,在androidx包中的Fragment和ComponentActivity都实现了这个接口。这个稍后再看

    继续看上面的代码,该构造方法调用了另一个构造方法

    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {  
        mFactory = factory;  
        mViewModelStore = store;  
    }
    

    mViewModelStore这个变量来自于ViewModelStoreOwner,接下来以Fragment为例,来看看

    public ViewModelStore getViewModelStore() {  
        if (mFragmentManager == null) {  
            throw new IllegalStateException("Can't access ViewModels from detached fragment");  
        }  
        return mFragmentManager.getViewModelStore(this);  
    }
    

    这里可以看出,Fragment的ViewModelStore是保存在当前实例下。先记住这个结论,待会还用得着。

    接下来看factory参数,fragment也是HasDefaultViewModelProviderFactory的实现类,因此获取factory的实例方法为

    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {  
        if (mFragmentManager == null) {  
            throw new IllegalStateException("Can't access ViewModels from detached fragment");  
        }  
        if (mDefaultFactory == null) {  
            mDefaultFactory = new SavedStateViewModelFactory(  
                requireActivity().getApplication(),  
                this,  
                getArguments());  
        }  
        return mDefaultFactory;  
    }
    

    这里的factory也是fragment中保存的实例

    回到ViewModelProvider的get方法

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

    最终调用的是

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

    这里获取缓存的viewmodel的方法 mViewModelStore.get(key)。这里的mViewModelStore就是fragment中存储的。

    讲到这里,其实已经清楚了生命周期的绑定过成了。

    在ViewModelProvider获取ViewModel的时候,实际上是从fragment中拿到的,如果fragment中没有的话,就创建一个,将其保存在fragment中。因此,只要拿到的fragment实例为同一个,无论新创建多少个ViewModelProvider的实例,最终获取的ViewModel都是同一个。而因为ViewModel的实例实际上是保存在fragment中,因此,viewmodel也会随fragment的销毁而销毁。

    相关文章

      网友评论

          本文标题:ViewModel源码阅读笔记

          本文链接:https://www.haomeiwen.com/subject/oswuirtx.html