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來創建一個

 

 

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