源码分析

Android ViewMode源码分析

2019-04-18  本文已影响0人  enjoy_coding

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()。好了到这里大概的流程就基本梳理完了,主要是有了这种思想之后再去回顾一下源码你就会感觉逻辑很清晰。

上一篇下一篇

猜你喜欢

热点阅读