美文网首页源码分析
Android ViewMode源码分析

Android ViewMode源码分析

作者: enjoy_coding | 来源:发表于2019-04-18 11:06 被阅读0次

    ViewMode的谷歌官方介绍如下:
    The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.
    翻译过来就是:ViewModel类旨在以生命周期意识的方式存储和管理与UI相关的数据。 ViewModel类允许数据在配置更改(例如屏幕旋转)后继续存在。

    既然谷歌官方说它有以生命周期意识,那我们就来看看它是怎么做到的;首先就是看它的基本用法,通过它的调用方式一层一层往下看它的源码实现;这个例子就采用谷歌官方的例子了,具体如下:

    class MyViewModel : ViewModel() {
        private val users: MutableLiveData<List<User>> by lazy {
            MutableLiveData().also {
                loadUsers()
            }
        }
    
        fun getUsers(): LiveData<List<User>> {
            return users
        }
    
        private fun loadUsers() {
            // Do an asynchronous operation to fetch users.
        }
    }
    

    这里我们先不要纠结它例子中的MutableLiveData和LiveData,这并不是我们的重点。
    定义好了模型我们就看怎么使用:

    class MyActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            // Create a ViewModel the first time the system calls an activity's onCreate() method.
            // Re-created activities receive the same MyViewModel instance created by the first activity.
    
            val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
            model.getUsers().observe(this, Observer<List<User>>{ users ->
                // update UI
            })
        }
    }
    

    使用过程中我们要关注文档上标红的警告:
    A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.
    警告:ViewModel绝不能引用视图,生命周期或任何可能包含对活动上下文的引用的类。

    以上就是ViewModel的使用,然而的生命周期如下图:


    viewmodel-lifecycle.png

    看了图片之后你可能会好奇她是怎么做到的呢,那接下来我们就通过它的使用方法来看它是怎么做到的。

    首先我们看ViewModelProviders.of(this)这个方法做了什么,点进去之后我们发现它调用了重载方法:

        @NonNull
        @MainThread
        public static ViewModelProvider of(@NonNull FragmentActivity activity) {
            return of(activity, null);
        }
    
        @NonNull
        @MainThread
        public static ViewModelProvider of(@NonNull FragmentActivity activity,
                @Nullable Factory factory) {
            Application application = checkApplication(activity);
            if (factory == null) {
                factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
            }
            return new ViewModelProvider(ViewModelStores.of(activity), factory);
        }
    

    这里我们只要关注下面的方法即可,第一行代码就是检查Application

      private static Application checkApplication(Activity activity) {
            Application application = activity.getApplication();
            if (application == null) {
                throw new IllegalStateException("Your activity/fragment is not yet attached to "
                        + "Application. You can't request ViewModel before onCreate call.");
            }
            return application;
        }
    

    当调用的时候传递的是fragment时,就会多调用一个方法如下:

    private static Activity checkActivity(Fragment fragment) {
            Activity activity = fragment.getActivity();
            if (activity == null) {
                throw new IllegalStateException("Can't create ViewModelProvider for detached fragment");
            }
            return activity;
        }
    

    当然了这两个方法对于我们调用和理解源码不太重要,就跳过了,最重要的是这个Factory和它的返回值,那下面我们就先来看看它的Factory是怎么创建的

      if (factory == null) {
                factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
       }
    

    点进去之后发现就是ViewModelProvider中的一个普通静态内部类,继承了ViewModelProvider中的NewInstanceFactory,这两个类代码如下:

         /**
         * Simple factory, which calls empty constructor on the give class.
         */
        public static class NewInstanceFactory implements Factory {
    
            @SuppressWarnings("ClassNewInstance")
            @NonNull
            @Override
            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                //noinspection TryWithIdenticalCatches
                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);
                }
            }
        }
         /**
         * {@link Factory} which may create {@link AndroidViewModel} and
         * {@link ViewModel}, which have an empty constructor.
         */
        public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
    
            private static AndroidViewModelFactory sInstance;
    
            /**
             * Retrieve a singleton instance of AndroidViewModelFactory.
             *
             * @param application an application to pass in {@link AndroidViewModel}
             * @return A valid {@link AndroidViewModelFactory}
             */
            @NonNull
            public static AndroidViewModelFactory getInstance(@NonNull Application application) {
                if (sInstance == null) {
                    sInstance = new AndroidViewModelFactory(application);
                }
                return sInstance;
            }
    
            private Application mApplication;
    
            /**
             * Creates a {@code AndroidViewModelFactory}
             *
             * @param application an application to pass in {@link AndroidViewModel}
             */
            public AndroidViewModelFactory(@NonNull Application application) {
                mApplication = application;
            }
    
            @NonNull
            @Override
            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);
            }
        }
    

    把它俩放一块对比之后你会发现原来这个简单,NewInstanceFactory就只有一个create方法,这个create()方法就直接通过Class创建了对象,而AndroidViewModelFactory的create()方法则是调用了一个传递了Application对象的方法。
    好了这个Factory是干啥的我们了解了之后我们就看这个ViewModelProvider是如何创建的,代码如下:

     return new ViewModelProvider(ViewModelStores.of(activity), factory);
    

    这行代码就是创建了一个ViewModelProvider,然后传递了两个参数一个是ViewModelStore,一个是上面分析的Factory,那接下来我们看看
    ViewModelStores.of(activity)干了啥,代码如下:

         /**
         * Returns the {@link ViewModelStore} of the given activity.
         *
         * @param activity an activity whose {@code ViewModelStore} is requested
         * @return a {@code ViewModelStore}
         */
        @NonNull
        @MainThread
        public static ViewModelStore of(@NonNull FragmentActivity activity) {
            if (activity instanceof ViewModelStoreOwner) {
                return ((ViewModelStoreOwner) activity).getViewModelStore();
            }
            return holderFragmentFor(activity).getViewModelStore();
        }
    

    首先它判断我们传递的FragmentActivity是不是ViewModelStoreOwner,并且ViewModelProvider的of()方法要求的类也是 FragmentActivity, 那么我们就得看看FragmentActivity这个类是不是实现了ViewModelStoreOwner接口或者继承了ViewModelStoreOwner这个类,点到FragmentActivity之后发现他已经实现了ViewModelStoreOwner接口,并重写了唯一的方法getViewModelStore();下面是FragmentActivity类中的实现:

    
        @NonNull
        public ViewModelStore getViewModelStore() {
            if (this.getApplication() == null) {
                throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
            } else {
                if (this.mViewModelStore == null) {
                    FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
                    if (nc != null) {
                        this.mViewModelStore = nc.viewModelStore;
                    }
    
                    if (this.mViewModelStore == null) {
                        this.mViewModelStore = new ViewModelStore();
                    }
                }
                return this.mViewModelStore;
            }
        }
    

    总之就是进行了一系列的校验之后判断是否已经有了ViewModelStore实例,如果没有就创建了ViewModelStore实例。

    看到这你大概应该也快晕了吧,这是什么鬼,调用来调用去,创建了这么多的对方,然而就只是创建了一个ViewModelProvider实例而已,对应我们的代码就是:

     ViewModelProviders.of(this)
    

    那接下来的问题就是ViewModelProvider的get()方法了,这个方法倒是简单,代码如下:

     @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) {
           //首先从mViewModelStore中获取,mViewModelStore内部就是存储了ViewModel的map,
           //key是android.arch.lifecycle.ViewModelProvider.DefaultKey:ViewModel类名
          //value是ViewModel实例
            ViewModel viewModel = mViewModelStore.get(key);
    //判断viewModel实例是否为空,不为空直接返回
            if (modelClass.isInstance(viewModel)) {
                //noinspection unchecked
                return (T) viewModel;
            } else {
                //noinspection StatementWithEmptyBody
                if (viewModel != null) {
                    // TODO: log a warning.
                }
            }
          //到这一步说明ViewModel还没有进行初始化,那么通过调用
         //前面分析传递的AndroidViewModelFactory对象实例调用create()方法创建实例,并保存进ViewModelStore中,方便下次直接获取
            viewModel = mFactory.create(modelClass);
            mViewModelStore.put(key, viewModel);
            //noinspection unchecked
            return (T) viewModel;
        }
    

    目前代码到这里我们就梳理出了ViewModel的创建过程和缓存机制,其实就是在自己创建的Activity的父类中的FragmentActivity中的ViewModelStore保存了跟activity相关的所有ViewModel对象,然后在FragmentActivity中的onDestroy()方法中对数据进行了清空,代码如下:

    //FragmentActivity中的onDestroy
    protected void onDestroy() {
           super.onDestroy();
           if (this.mViewModelStore != null && !this.isChangingConfigurations()) {
               this.mViewModelStore.clear();
           }
           this.mFragments.dispatchDestroy();
       }
    
       //ViewModelStore中的clear()
       /**
        *  Clears internal storage and notifies ViewModels that they are no longer used.
        */
       public final void clear() {
           for (ViewModel vm : mMap.values()) {
               vm.onCleared();
           }
           mMap.clear();
       }
    

    到这里我们就看到了它是如何跟activity的生命周期进行绑定的;其实就是系统在FragmentActivity中自定义了一个Map,然后保存了跟这个Activity相关的ViewModel,在onDestroy的时候对这个Map进行了清空数据操作,在进行清空之前对Activity的重新创建进行了判断,就是调用了!this.isChangingConfigurations()。好了到这里大概的流程就基本梳理完了,主要是有了这种思想之后再去回顾一下源码你就会感觉逻辑很清晰。

    相关文章

      网友评论

        本文标题:Android ViewMode源码分析

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