Android Architecture Components 之 ViewModel的源码分析

ViewModel

参考:https://blog.csdn.net/u010072711/article/details/80035276

创建

val viewModelProvider = ViewModelProviders.of(_mActivity,viewModelFactory)
val manageViewModel = viewModelProvider.get(ManageViewModel::class.java)
​

源码分析ViewModel创建流程

查看ViewModelProviders类

/**
     *
     * @param activity
     * @param factory 提供了自定义创建ViewModel的方法
     * @return
     */
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity,
                                       @NonNull ViewModelProvider.Factory factory) {
        //检测activity
        checkApplication(activity);
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }
  • 存在是依赖 Activity 或者 Fragment的,不管你在什么地方获取ViewModel ,只要你用的是相同的Activity 或者 Fragment,那么获取到的ViewModel将是同一个 (前提是key值是一样的),所以ViewModel 也具有数据共享的作用!

  • 每次获取ViewModel都是重新new ViewModelProvider

第一个参数ViewModelStores.of(activity)

    @MainThread
    public static ViewModelStore of(@NonNull FragmentActivity activity) {
        //如果你的Activity实现了ViewModelStoreOwner接口具备了提供
        //ViewModelStore 的功能就直接获取返回,通常我们的Activity都不会去实现这个功能
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        //系统为你的Activity添加一个具有提供ViewModelStore 的holderFragment
        return holderFragmentFor(activity).getViewModelStore();
    }

如果你的Activity实现了ViewModelStoreOwner接口具备了提供ViewModelStore 的功能就直接获取返回,通常我们的Activity都不会去实现这个功能;如果没有,则系统为你的Activity添加一个具有提供ViewModelStore 的holderFragment

总结:最终每一个Activity或者Fragment都有一个ViewModelStore,而这个ViewModelStore是存储ViewModel的

第二个参数factory,下面是自定义的ViewModelFactory kotlin写法

@Singleton
class ViewModelFactory @Inject constructor(
        private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val creator = creators[modelClass] ?: creators.entries.firstOrNull {
            modelClass.isAssignableFrom(it.key)
        }?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
        try {
            @Suppress("UNCHECKED_CAST")
            return creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}
  • 实现 ViewModelProvider.Factory,

  • 构造传入Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>

  • create方法根据Class,从map中获取Provider<ViewModel>,再从Provider<ViewModel>中get得到ViewModel

解析viewModelProvider.get(ManageViewModel::class.java)

@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) {
        ViewModel viewModel = mViewModelStore.get(key);
​
        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
​
        viewModel = mFactory.create(modelClass);
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }
​

流程是:

  • 先从mViewModelStore中使用key去获取ViewModel, mViewModelStore中是使用HashMap去存储一个Activity或者FragmentViewModel的。如果获取到就返回

  • 没获取到就使用单例mFactory的create方法反射创建ViewModel,create方法的代码在上面贴出来了。

  • 使用Key存入mViewModelStore 并返回

解析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);
    }
​
    /**
     *  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();
    }
}

大概内容是:

一个 HashMap用存储ViewModel。提供get,put,clear三个方法。 上面说了ViewModelStore是每一个Activity或者ViewModel都有一个的,当Activity或者Fragment销毁的时候就会调用clear方法了。

  • ViewModelStore被HolderFragment创建和持有

  • 当我们要给Activity或者Fragment创建ViewModel的时候,系统就会为Activity或者Fragment添加一个HolderFragmentHolderFragment中会创建持有一个ViewModelStore

结合Dagger2

​
    @Binds
    @IntoMap
    @ViewModelKey(HealthViewModel::class)
    abstract fun bindHealthViewModel(healthViewModel: HealthViewModel): ViewModel
​
    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel::class)
    abstract fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel
​
    @Binds
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
  • @Bind 和 @Provider的作用相差不大,区别在于@Provider需要写明具体的实现,而@Binds只是告诉Dagger2谁是谁实现的

  • @IntoMap 则可以让Dagger2将多个元素依赖注入到Map之中

  • @ViewModelKey(MainViewModel::class) Dagger2会根据这些信息自动生成一个关键的Map。key为ViewModel的Class,value则为提供ViewModel实例的Provider对象,通过provider.get()方法就可以获取到相应的ViewModel对象

上面ViewModelFactory的分析有,看到他的构造是map,而通过dagger2 的@IntoMap @ViewModelKey()可生成一个map,正好为ViewModelFactory的创建提供参数,同时发现在ViewModelProviders.of(this)中发现默认的factory每次传入都是单例的,所以在ViewModelFactory用@Singleton来修饰

总结ViewModel的创建流程是

  • new ViewModelProvider,传入两个参数,一个是ViewModelStore,一个是ViewModelProvider.Factory,

  • ViewModelStore由,当要给Activity或者Fragment创建ViewModel的时候,系统就会为Activity或者Fragment添加一个HolderFragmentHolderFragment中会创建持有一个ViewModelStore

  • 当ViewModelProvider.get()时,先查看ViewModelStore是否存储有,有则返回,无则通过Factory来创建一个

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章