1、相關的類
- ViewModelStore :管理viewModel實例,內部包含一個Map用來存儲viewmodel,內部包括put、get、clear等方法
- ViewModelProvider :管理ViewModelStore和Factory,Factory里面有create方法是創建對應的viewmodel的,ViewModelProvider內部有一個get方法獲取viewmodel
2、在項目中應用
首先新建項目分別創建TestViewModel
TestViewModel.class
fun provideFactory(repository: TestRepository): ViewModelProvider.Factory = object : ViewModelProvider.Factory {@Suppress("UNCHECKED_CAST")override fun <T : ViewModel> create(modelClass: Class<T>): T {return TestViewModel(repository) as T}}
MainActivity.class中初始化代碼:
private val testViewModel by viewModels<TestViewModel> {TestViewModel.provideFactory(TestRepository())}
接下來在MainActivity里面就可以正常使用這個viewmodel了
3、流程簡單解析
首先我們在mainActivity里面初始化時候使用了by viewmodel 這個方式進行初始化點擊進入這個方法之后源碼如下:
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(noinline extrasProducer: (() -> CreationExtras)? = null,noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {val factoryPromise = factoryProducer ?: {defaultViewModelProviderFactory}return ViewModelLazy(VM::class,{ viewModelStore },factoryPromise,{ extrasProducer?.invoke() ?: this.defaultViewModelCreationExtras })
}
可以看到viewModels是ComponentActivity的一個擴展函數,參數需要傳factoryProducer,factoryProducer就是前面我們提到過的ViewModelProvider的內部的一個factory類,用來創建viewModel的,所以我們傳入TestViewModel.provideFactory。
繼續向下看進入ViewModelLazy:
public class ViewModelLazy<VM : ViewModel> @JvmOverloads constructor(private val viewModelClass: KClass<VM>,private val storeProducer: () -> ViewModelStore,private val factoryProducer: () -> ViewModelProvider.Factory,private val extrasProducer: () -> CreationExtras = { CreationExtras.Empty }
) : Lazy<VM> {private var cached: VM? = nulloverride val value: VMget() {val viewModel = cachedreturn if (viewModel == null) {val factory = factoryProducer()val store = storeProducer()ViewModelProvider(store,factory,extrasProducer()).get(viewModelClass.java).also {cached = it}} else {viewModel}}override fun isInitialized(): Boolean = cached != null
}
首先判斷是否有緩存,如果有緩存直接返回,無緩存情況下就去ViewModelProvider獲取對應的viewmodel并且進行一下緩存操作,接下來我們看一下ViewModelProvider的get方法
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {val viewModel = store[key]if (modelClass.isInstance(viewModel)) {(factory as? OnRequeryFactory)?.onRequery(viewModel!!)return viewModel as T} else {@Suppress("ControlFlowWithEmptyBody")if (viewModel != null) {// TODO: log a warning.}}val extras = MutableCreationExtras(defaultCreationExtras)extras[VIEW_MODEL_KEY] = key// AGP has some desugaring issues associated with compileOnly dependencies so we need to// fall back to the other create method to keep from crashing.return try {factory.create(modelClass, extras)} catch (e: AbstractMethodError) {factory.create(modelClass)}.also { store.put(key, it) }}
get方法通過內部的store傳入類名來獲取view model,那么store是從哪里來的呢?往回看能看到是在ComponentActivity.viewModels這里返回了一個ViewModelLazy時傳入了viewModelStore,這個viewModelStore是從ComponentActivity初始化時候就創建了的
public ComponentActivity() {//......getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {// Clear out the available contextmContextAwareHelper.clearAvailableContext();// And clear the ViewModelStoreif (!isChangingConfigurations()) {getViewModelStore().clear();}mReportFullyDrawnExecutor.activityDestroyed();}}});getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {ensureViewModelStore();getLifecycle().removeObserver(this);}});//......}void ensureViewModelStore() {if (mViewModelStore == null) {NonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();if (nc != null) {// Restore the ViewModelStore from NonConfigurationInstancesmViewModelStore = nc.viewModelStore;}if (mViewModelStore == null) {mViewModelStore = new ViewModelStore();}}}
在activity創建時添加生命周期監聽,生命周期變更時創建ViewModelStore,當生命周期destory時會通過isChangingConfigurations來判斷是否是通過切換橫豎屏導致的destroy,如果是的話不會對view model執行clear,這樣保證了view model在切換橫豎屏時依然可以保存數據,等頁面真正的退出執行的destroy時才會對viewmodel執行clear方法,這樣保證了viewmodel的生命周期和activity一致,也不需要我們單獨對其生命周期進行維護。
針對這個流程簡單的分析,如有分析不符的地方歡迎評論指正