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
或者Fragment
的ViewModel
的。如果獲取到就返回 -
沒獲取到就使用單例
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添加一個
HolderFragment
,HolderFragment
中會創建持有一個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添加一個
HolderFragment
,HolderFragment
中會創建持有一個ViewModelStore
-
當ViewModelProvider.get()時,先查看ViewModelStore是否存儲有,有則返回,無則通過Factory來創建一個