美文网首页
Android Architecture Component源码

Android Architecture Component源码

作者: 珞泽珈群 | 来源:发表于2019-05-19 00:16 被阅读0次

    目录

    源码解析目录

    问题

    用过AAC的人都知道,ViewModel的使用是很简单的,没有太多复杂的东西,而ViewModel本身的源码也异常简单。真正“神奇”的地方在于ViewModel的生命周期:

    在Activity的configuration(配置)发生变化时,Activity会被重建,但是ViewModel却不会,直至Activity真正消失的时候,ViewModel的onCleared方法才会被调用。这就是我们的核心问题,这一切是怎么实现的?
    (源码版本androidx.lifecycle:lifecycle-viewmodel:2.2.0

    1. ViewModel的获取

    ViewModel本身是异常简单的:

    public abstract class ViewModel {
    
        protected void onCleared() {
        }
    
    }
    

    ViewModel就是这样,仅仅包含一个onCeared方法(最初的ViewModel的确只有这一个方法,后来又增加了一些方法,但是这些方法都不是给我们使用的,所以可以忽略)。
    AAC给我们提供的获取ViewModel的方法很简单:
    ViewModelProvider(activity/fragment).get(ViewModel.class) (之前更常见的一种方式是ViewModelProviders.of(activity/fragment).get(ViewModel.class),但是现在这种方式已经被删除了)。

    我们来看一下ViewModelProvider是怎么实现的:

    @SuppressWarnings("WeakerAccess")
    public class ViewModelProvider {
    
        private static final String DEFAULT_KEY =
                "androidx.lifecycle.ViewModelProvider.DefaultKey";
    
        /**
         * 创建ViewModel的Factory
         */
        public interface Factory {
            @NonNull
            <T extends ViewModel> T create(@NonNull Class<T> modelClass);
        }
    
        private final Factory mFactory;
        private final ViewModelStore mViewModelStore;
    
        public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
            //这里的ViewModelStoreOwner 一般而言不是Activity就是Fragment,并且它们都实现了HasDefaultViewModelProviderFactory,也就是说Activity/Fragment都会提供默认的ViewModelFactory
            this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                    ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                    : NewInstanceFactory.getInstance());
        }
    
        /**
         * @param store   ViewModel存储的地方
         * @param factory ViewModel构建的地方
         */
        public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
            mFactory = factory;
            mViewModelStore = store;
        }
    
        /**
         * 如果不提供key,默认的key就是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);
        }
    
        /**
         * 如果ViewModel在ViewModelStore中已经存在,则可以直接返回使用
         * 如果不存在,则通过Factory新建,默认的工厂是SavedStateViewModelFactory,新建ViewModel的方式是反射
         */
        @NonNull
        @MainThread
        public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
            ViewModel viewModel = mViewModelStore.get(key);
    
            if (modelClass.isInstance(viewModel)) {
                //给你一个机会再重新获取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);
            //noinspection unchecked
            return (T) viewModel;
        }
    }
    

    总结一下ViewModelProvider的作用。ViewModelProvider是我们获取ViewModel的地方,创建ViewModelProvider需要我们提供两个参数:1. ViewModelStore 2. ViewModelProvider.Factory。它们的作用也很明了,分别用来存储ViewModel和创建ViewModel。首先在ViewModelStore中查找,没有的话再通过Factory创建。
    ViewModelProviderget方法是可以提供一个key来说明我们需要的是哪个ViewModel。不过,我们可能不常提供,不提供的话默认的key是ViewModel的类名(前面加了一个前缀)。如果我们的Activity或者Fragment需要同一种ViewModel类的两个对象时,key的作用就很明显了。

    2. ViewModel的创建和存储

    2.1 ViewModelProvider.Factory

    默认的ViewModelProvider.Factory是SavedStateViewModelFactory,从这个名字可以看出,这是一个可以为ViewModel提供SavedState的Factory,ViewModel的SavedState是2.x版本新添加的功能,目的是为了在ViewModel中方便的保存状态,在Activity重建的时候使用。不了解这些没关系,因为如果你不使用这个SavedState功能的话,这个SavedStateViewModelFactory其实会退化成AndroidViewModelFactory,它只是通过反射创建ViewModel而已。这要求我们的ViewModel必须有默认构造函数。从ViewModel的生命周期图上可以看出,ViewModel的生命周期要比Activity或者Fragment的更长,ViewModel中自然就不能包含Activity或者Fragment,如果实在需要在ViewModel中使用Context,那么只能使用ApplicationContext,为了方便我们使用,AAC中还定义了一个AndroidViewModel

    public class AndroidViewModel extends ViewModel {
        @SuppressLint("StaticFieldLeak")
        private Application mApplication;
    
        public AndroidViewModel(@NonNull Application application) {
            mApplication = application;
        }
    
        /**
         * Return the application.
         */
        @SuppressWarnings("TypeParameterUnusedInFormals")
        @NonNull
        public <T extends Application> T getApplication() {
            //noinspection unchecked
            return (T) mApplication;
        }
    }
    

    我们的ViewModel也可以继承自AndroidViewModel,这样在ViewModel中就可以方便地使用Application了。而AndroidViewModelFactory也可以通过反射创建继承自AndroidViewModel的ViewModel。
    想了解更多关于ViewModel-SavedState的内容,可以查看这篇文章ViewModel如何保存状态——SavedState源码解析

    2.2 ViewModelStore

    兼容包中的Activity和Fragment皆实现了ViewModelStoreOwner接口,该接口只包含一个方法getViewModelStore

    2.2.1 Activity与ViewModelStore

    public class ComponentActivity implements ViewModelStoreOwner {
    
        static final class NonConfigurationInstances {
            Object custom;
            ViewModelStore viewModelStore;
        }
        
        // 延迟创建,直到 getViewModelStore() 被调用时才会被创建
        private ViewModelStore mViewModelStore;
        
        /**
         * 保留所有的 non-config state. 不随配置变化的那些变量。
         * 最重要的就是保留了 ViewModelStore
         */
        @Override
        @Nullable
        public final Object onRetainNonConfigurationInstance() {
            Object custom = onRetainCustomNonConfigurationInstance();
    
            ViewModelStore viewModelStore = mViewModelStore;
            if (viewModelStore == null) {
                // No one called getViewModelStore(), so see if there was an existing
                // ViewModelStore from our last NonConfigurationInstance
                NonConfigurationInstances nc =
                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                if (nc != null) {
                    viewModelStore = nc.viewModelStore;
                }
            }
    
            if (viewModelStore == null && custom == null) {
                return null;
            }
    
            NonConfigurationInstances nci = new NonConfigurationInstances();
            nci.custom = custom;
            nci.viewModelStore = viewModelStore;
            return nci;
        }
        
        /**
         * 从 NonConfigurationInstances 中取出 viewModelStore
         * 没有则新建一个 ViewModelStore
         */
        @NonNull
        @Override
        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 nc =
                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                if (nc != null) {
                    // Restore the ViewModelStore from NonConfigurationInstances
                    mViewModelStore = nc.viewModelStore;
                }
                if (mViewModelStore == null) {
                    mViewModelStore = new ViewModelStore();
                }
            }
            return mViewModelStore;
        }
    }
    

    对于Activity而言,它本身就包含有一个ViewModelStore,在调用getViewModelStore方法时会被创建(如果需要的话)。ViewModel最神奇的地方就是它不会随配置的变化而重建,表现在生命周期上就是文中的第一幅图。这一切是怎么实现的呢?在上述代码中我们已经可以看出来了。Activity的ViewModelStore会在配置发生变化时通过onRetainNonConfigurationInstance方法被保留下来,在getViewModelStore方法中又首先会从NonConfigurationInstances中取出被保留下来的ViewModelStore(如果有的话)。这样,ViewModelStore就不会因为配置的变化而重建,也就是说,我们的ViewModel不受配置变化的影响。

    2.2.2 Fragment与ViewModelStore

    public class Fragment implements ViewModelStoreOwner {
    
        //自身并没有实现,委托给了FragmentManager
        @NonNull
        @Override
        public ViewModelStore getViewModelStore() {
            if (mFragmentManager == null) {
                throw new IllegalStateException("Can't access ViewModels from detached fragment");
            }
            return mFragmentManager.getViewModelStore(this);
        }
    }
    

    再来看看FragmentManager

    final class FragmentManagerImpl extends FragmentManager {
        private FragmentManagerViewModel mNonConfig;
        
        //又委托给了mNonConfig
        @NonNull
        ViewModelStore getViewModelStore(@NonNull Fragment f) {
            return mNonConfig.getViewModelStore(f);
        }
        
        /**
         * 这个方法会在上述方法 getViewModelStore 之前被调用,是mNonConfig被赋值的地方
         * 其中host一般情况下是我们的Activity
         * parent是指父Fragment
         */
        public void attachController(@NonNull FragmentHostCallback host,
                                     @NonNull FragmentContainer container, @Nullable Fragment parent) {
            if (mHost != null) throw new IllegalStateException("Already attached");
            mHost = host;
            mContainer = container;
            mParent = parent;
            if (parent != null) { //父Fragment不为null,则从父Fragment的FragmentManager中获取NonConfig
                mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
            } else if (host instanceof ViewModelStoreOwner) {
                //host是我们的Activity,它的确实现了ViewModelStoreOwner接口
                ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
                mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
            } else {
                mNonConfig = new FragmentManagerViewModel(false);
            }
        }
    }
    

    Fragment将getViewModelStore委托给了其FragmentManager,FragmentManager又把getViewModelStore委托给了NonConfig。从NonConfig这个名字可以猜测出,它应该是保存Fragment中与配置无关的变量的地方(比如说我们的ViewModelStore)。而NonConfig的类型却是FragmentManagerViewModel,用一个ViewModel去保存ViewModelStore,这是什么骚操作?

    看看FragmentManagerViewModel就知道了

    /**
     * FragmentManagerViewModel is the always up to date view of the Fragment's non configuration state
     * FragmentManagerViewModel保存了最新的Fragment的non configuration state
     */
    class FragmentManagerViewModel extends ViewModel {
    
        private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
            @NonNull
            @Override
            @SuppressWarnings("unchecked")
            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                FragmentManagerViewModel viewModel = new FragmentManagerViewModel(true);
                return (T) viewModel;
            }
        };
    
        /**
         * 从上一段代码中可以看出,此处的ViewModelStore其实就是Activity中的ViewModelStore
         * 也就是说这个FragmentManagerViewModel是被保存在Activity的ViewModelStore中的
         */
        @NonNull
        static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
            ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
                    FACTORY);
            return viewModelProvider.get(FragmentManagerViewModel.class);
        }
    
        //保存子Fragment的NonConfig,对于我们而言,其实就是保存子Fragment的ViewModelStore
        private final HashMap<String, FragmentManagerViewModel> mChildNonConfigs = new HashMap<>();
        //保存Fragment的ViewModelStore
        private final HashMap<String, ViewModelStore> mViewModelStores = new HashMap<>();
    
        
        @NonNull
        FragmentManagerViewModel getChildNonConfig(@NonNull Fragment f) {
            FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
            if (childNonConfig == null) {
                childNonConfig = new FragmentManagerViewModel(mStateAutomaticallySaved);
                mChildNonConfigs.put(f.mWho, childNonConfig);
            }
            return childNonConfig;
        }
    
        @NonNull
        ViewModelStore getViewModelStore(@NonNull Fragment f) {
            ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
            if (viewModelStore == null) {
                viewModelStore = new ViewModelStore();
                mViewModelStores.put(f.mWho, viewModelStore);
            }
            return viewModelStore;
        }
    }
    

    如注释所说,FragmentManagerViewModel的作用是保存Fragment最新的non configuration state,我们要保存的Fragment的ViewModelStore也是non configuration state,保存在FragmentManagerViewModel中正合适。但是,FragmentManagerViewModel是怎么做到这一点的呢?答案很简单,把FragmentManagerViewModel放到Activity的ViewModelStore中,我们上面已经分析过了,Activity的ViewModelStore在配置发生变化时会被保留下来,所以FragmentManagerViewModel自然也就不受配置变化的影响。想想也是,FragmentManagerViewModel也就是个普通的ViewModel,自然拥有ViewModel的特点,只不过AAC正好利用了这一点,把它用来保存Fragment的non configuration state(我们最关心的Fragment的ViewModelStore也在其中)。

    Activity的ViewModelStore是不随配置变化的,Fragment的ViewModelStore也自然不随配置变化。

    2.2.3 ViewModelStore

    说了这么多ViewModelStore,到底ViewModelStore长啥样?显然ViewModelStore就是存储ViewModel的地方。如前所述,我们实际上是通过字符串key去获取的ViewModel,那么ViewModelStore自然是以Map的形式来存储ViewModel。嗯,基本上这就是ViewModelStore的全部,就是这么简单。

    public class ViewModelStore {
    
        private final HashMap<String, ViewModel> mMap = new HashMap<>();
    
        final void put(String key, ViewModel viewModel) {
            ViewModel oldViewModel = mMap.put(key, viewModel);
            if (oldViewModel != null) {
                oldViewModel.onCleared();
            }
        }
    
        final ViewModel get(String key) {
            return mMap.get(key);
        }
    
        Set<String> keys() {
            return new HashSet<>(mMap.keySet());
        }
    
        /**
         *  会在Activity、Fragment destroy并且不是因为配置发生变化的时候被调用
         */
        public final void clear() {
            for (ViewModel vm : mMap.values()) {
                vm.clear();
            }
            mMap.clear();
        }
    }
    

    3. 隐藏技能

    1. 如果我们需要在同一个Activity或者Fragment中创建多个同一类型的ViewModel,我们可以在获取ViewModel的时候用不同的key进行区分。
    2. 默认情况下AndroidViewModelFactory会帮我们以反射的方式创建ViewModel,但是ViewModel是在View和Model之间起到桥梁的作用,ViewModel一般情况下都需要包含Model层,而使用AndroidViewModelFactory又要求我们的ViewModel必须包含默认构造函数(AndroidViewModel情况除外),这就导致我们不能使用构造函数的方式去注入Model层,有时候这很不方便。还好,我们可以提供自己的ViewModelProvider.Factory。恰好,dagger2有一种能力叫作MultiBindings,是以依赖注入创建ViewModelProvider.Factory的绝佳方式,详见当Dagger2撞上ViewModel
    3. 你可能觉得Activity的onRetainNonConfigurationInstance是个保存NonConfig State的好地方,如果我们也有什么不随配置变化的变量,也可以利用onRetainNonConfigurationInstance来保存,甚至Activity中有个方法叫onRetainCustomNonConfigurationInstance,专门帮我们保存自己的NonConfig State。恭喜你,从源码中又学到了一点没有卵用的东西。Activity觉得你很聪明,并向你扔出一个Deprecated警告。onRetainCustomNonConfigurationInstance方法已经被标记为废弃的,并推荐你使用ViewModel来保存NonConfig State。至于原因,不言自明。

    4. 总结

    ViewModel要解决的核心问题是怎样在配置发生变化时保留ViewModel。利用Activity提供的onRetainNonConfigurationInstance方法,可以方便的保留不受配置变化影响的数据。
    在实现了Activity的ViewModelStore之后,我们便可以利用ViewModel本身的特点去保存Fragment的ViewModelStore,如此这般,Fragment的ViewModel便也不再受配置变化的影响。用Activity中的ViewModelStore去保存FragmentManagerViewModel,而FragmentManagerViewModel又保存了Fragment的ViewModelStore。嗯,真真是踩在自己的肩膀上向上爬。

    相关文章

      网友评论

          本文标题:Android Architecture Component源码

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