Jetpack系列:
Lifecycle使用方法、原理分析 - 掘金 (juejin.cn)
LiveData使用方法、原理分析 - 掘金 (juejin.cn)
ViewModel使用方法、原理分析(一) - 掘金 (juejin.cn)
ViewModel使用方法、原理分析(二) - 掘金 (juejin.cn)
自定义View中获取ViewModel - 掘金 (juejin.cn)
ViewModel基本使用
/**
* 携带自定义参数的ViewModel,创建时需要创建自定义ViewModelProvider.Factory
*
**/
class CustomViewModel(name: String?):ViewModel() {
private val _data1 = MutableLiveData("A")
val data1:LiveData<String> = _data1
}
/**
* ComponentActvity、Fragment默认的SavedStateViewModelFactory
* 将Intent.getBundle() & Fragment.getArugment()作为参数在ViewModel反射时传递
* 优点:可获取Activity跳转时携带的参数
**/
class CustomViewModel(savedStateHandle: SavedStateHandle?):ViewModel() {
private val _data1 = MutableLiveData("A")
val data1:LiveData<String> = _data1
init {
val param = savedStateHandle.get<String>("param")
Log.d("TAG", "===========param:$param")
}
}
class CustomViewActivity:ComponentActivity() {
//方法1:Kotlin 语法糖形式创建ViewModel,还是调用ViewModelProvider.get()
private val viewModel by viewModels<CustomViewModel>()
//需注意方法2&方法3 初始化操作需要在Activity OnCreate之后执行
//方法2:ViewModelProvider创建ViewModel,不带工厂Factory,不能携带初始化参数
private val viewModel1 = ViewModelProvider(this)[CustomViewModel::class.java]
//方法3:ViewModelProvider创建ViewModel,带工厂Factory,可携带初始化参数
private val viewModel2 = ViewModelProvider(this, CustomViewModelFactory())[CustomViewModel::class.java]
private class CustomViewModelFactory() : ViewModelProvider.Factory{
private val name = "CustomViewModel"
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return CustomViewModel("") as T
}
}
}
ViewModel原理分析
ViewModelStore
ViewModelStore 一种缓存机制,通过键值对的形式来缓存 ViewModel 对象,key取值为ViewModel类名
DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"+ modelClass.canonicalName
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);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
ViewModelStoreOwner
ComponentActivity为其实现类(AppCompatActivity继承FragmentActivity继承ComponentActivity),实现了 ViewModelStoreOwner 接口的组件内部会自动创建 ViewModelStore, ViewModel 对象会缓存到 ViewModelStore 这些组件产生了绑定关系, NonConfigurationInstances是实现Activity配置发生改变时,ViewModel保存数据的关键
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
/**
* ComponentActivity类中关于实现ViewModelOwner接口,ensureViewModelStore()初始化ViewModelStore
*
*
*/
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
ensureViewModelStore();
return mViewModelStore;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
ViewModelProvider
用来创建ViewModel,通过Android官方源码提供的创建ViewModel作为入口进行分析
val viewmodel: MyViewModel by viewmodels()
/**
* CompentActivity扩展函数,可以传入Factory作为参数用于创建ViewModel,CompentActivity实现
* HasDefaultViewModelProviderFactory接口,可以获取默认Factory对象为SaveStateViewModelFactory
*
**/
@MainThread
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
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? = null
override val value: VM
get() {
val viewModel = cached
return 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对象,创建过程如下:
@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
val canonicalName = modelClass.canonicalName
?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
return get("$DEFAULT_KEY:$canonicalName", modelClass)
}
@Suppress("UNCHECKED_CAST")
@MainThread
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) }
}
/**
* 工厂类接口
*
**/
public interface Factory {
public fun <T : ViewModel> create(modelClass: Class<T>): T {
throw UnsupportedOperationException(
"Factory.create(String) is unsupported. This Factory requires " +
"`CreationExtras` to be passed into `create` method."
)
}
public fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T =
create(modelClass)
}
/**
* 工厂类接口两个自带实现类,
* NewInstanceFactory、AndroidViewModelFactory分别用于创建自定义ViewModel、AndroidViewModel
*
**/
public open class NewInstanceFactory : Factory {
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return try {
modelClass.newInstance()
} catch (e: InstantiationException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
}
public companion object {
private var sInstance: NewInstanceFactory? = null
@JvmStatic
public val instance: NewInstanceFactory
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
get() {
if (sInstance == null) {
sInstance = NewInstanceFactory()
}
return sInstance!!
}
private object ViewModelKeyImpl : Key<String>
@JvmField
val VIEW_MODEL_KEY: Key<String> = ViewModelKeyImpl
}
}
public open class AndroidViewModelFactory
private constructor(
private val application: Application?,
@Suppress("UNUSED_PARAMETER") unused: Int,
) : NewInstanceFactory() {
@Suppress("SingletonConstructor")
public constructor() : this(null, 0)
@Suppress("SingletonConstructor")
public constructor(application: Application) : this(application, 0)
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
return if (application != null) {
create(modelClass)
} else {
val application = extras[APPLICATION_KEY]
if (application != null) {
create(modelClass, application)
} else {
// For AndroidViewModels, CreationExtras must have an application set
if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
throw IllegalArgumentException(
"CreationExtras must have an application by `APPLICATION_KEY`"
)
}
super.create(modelClass)
}
}
}
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return if (application == null) {
throw UnsupportedOperationException(
"AndroidViewModelFactory constructed " +
"with empty constructor works only with " +
"create(modelClass: Class<T>, extras: CreationExtras)."
)
} else {
create(modelClass, application)
}
}
@Suppress("DocumentExceptions")
private fun <T : ViewModel> create(modelClass: Class<T>, app: Application): T {
return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
try {
modelClass.getConstructor(Application::class.java).newInstance(app)
} catch (e: NoSuchMethodException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: InstantiationException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: InvocationTargetException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
} else super.create(modelClass)
}
public companion object {
internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
if (owner is HasDefaultViewModelProviderFactory)
owner.defaultViewModelProviderFactory else instance
internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"
private var sInstance: AndroidViewModelFactory? = null
@JvmStatic
public fun getInstance(application: Application): AndroidViewModelFactory {
if (sInstance == null) {
sInstance = AndroidViewModelFactory(application)
}
return sInstance!!
}
private object ApplicationKeyImpl : Key<Application>
@JvmField
val APPLICATION_KEY: Key<Application> = ApplicationKeyImpl
}
}
SaveStateViewModelFactory
CompentActivity、Fragment中持有SaveStateViewModelFactory,通过SaveStateViewModelFactory生成ViewModel,携带Intent&Argument参数,用与创建携带SavedStateHandle的ViewModel
private val ANDROID_VIEWMODEL_SIGNATURE = listOf<Class<*>>(
Application::class.java,
SavedStateHandle::class.java
)
private val VIEWMODEL_SIGNATURE = listOf<Class<*>>(SavedStateHandle::class.java)
fun <T : ViewModel> create(key: String, modelClass: Class<T>): T {
// empty constructor was called.
if (lifecycle == null) {
throw UnsupportedOperationException(
"SavedStateViewModelFactory constructed with empty constructor supports only " +
"calls to create(modelClass: Class<T>, extras: CreationExtras)."
)
}
val isAndroidViewModel = AndroidViewModel::class.java.isAssignableFrom(modelClass)
val constructor: Constructor<T>? = if (isAndroidViewModel && application != null) {
findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE)
} else {
findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE)
}
// doesn't need SavedStateHandle
if (constructor == null) {
// If you are using a stateful constructor and no application is available, we
// use an instance factory instead.
return if (application != null) factory.create(modelClass)
else instance.create(modelClass)
}
val controller = LegacySavedStateHandleController.create(
savedStateRegistry, lifecycle, key, defaultArgs
)
val viewModel: T = if (isAndroidViewModel && application != null) {
newInstance(modelClass, constructor, application!!, controller.handle)
} else {
newInstance(modelClass, constructor, controller.handle)
}
viewModel.setTagIfAbsent(
AbstractSavedStateViewModelFactory.TAG_SAVED_STATE_HANDLE_CONTROLLER, controller
)
return viewModel
}
internal fun <T : ViewModel?> newInstance(
modelClass: Class<T>,
constructor: Constructor<T>,
vararg params: Any
): T {
return try {
constructor.newInstance(*params)
} catch (e: IllegalAccessException) {
throw RuntimeException("Failed to access $modelClass", e)
} catch (e: InstantiationException) {
throw RuntimeException("A $modelClass cannot be instantiated.", e)
} catch (e: InvocationTargetException) {
throw RuntimeException(
"An exception happened in constructor of $modelClass", e.cause
)
}
}