ViewModel原理解析
ViewModel的出现是为了解决什么问题?
为了代码的可读性和可维护性,我们在设计程序架构时,会以各种模式来进行设计,以实现程序的高内聚,低耦合,进行业务分层。如MVC、MVP、MVVM。
最初的MVC模式,model/view/contorle,model数据层、view界面层、control控制层。model为数据层用来处理数据,view界面层用来显示view,这里的view包括activity/fragment/view等,里面会编写界面逻辑和部分业务逻辑。control控制层主要是业务逻辑代码。
为了更好的管理生命周期,MVP模式应运而生,MVP面向接口编程,分为model/view/persenter,view和persenter之间通过接口传递数据、不直接持有对方的实例对象,减少了内存溢出,同时能更好的管理生命周期。但弊端是接口数量爆炸,后期维护成本高。
这个时候ViewModel出现了,ViewModel可以帮你管理生命周期,并且在屏幕旋转等造成的Activity/fragment生命周期变化,ViewModel的实例也不会销毁重建、直到activity/fragment销毁,viewModel才会销毁。MVVM模式就是model/view/viewModel,view/viewModel使得程序符合关注点分离原则,view只负责显示数据、viewModel只用来处理业务逻辑。
ViewModel的基本使用
首先来看怎么使用ViewModel
1.创建继承自ViewModel的子类
class MainFragmentViewModel : ViewModel() {}
2.在Activity/fragment中获取ViewModel实例对象,这里以fragment为例
val viewMode: MainFragmentViewModel = ViewModelProvider(this).get(MainFragmentViewModel::class.java)
3.接下来就可以通过viewModel对象调用其中的方法了。
ViewModel源码解析
通过ViewModel的基本使用可以看到,获取ViewModel的实例对象需要通过构造方法创建ViewModelProvider实例,并调用get方法。
1.首先看ViewModelProvider的构造方法
/**
*Creates ViewModelProvider. This will create ViewModels and retain
*them in a store of the given ViewModelStoreOwner.
*This method will use the default factory if the owner implements
*HasDefaultViewModelProviderFactory. Otherwise, a NewInstanceFactory
*will be used.
**/
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner))
通过构造方法可以看出,需要一个ViewModelStoreOwner类型的参数,而Activity/fragment实现了ViewMoelStoreOwner接口,所以activity/fragment对象可以作为参数入参
接下来调用了this方法,即调用了该类构造方法的重载方法
public open class ViewModelProvider(
private val store: ViewModelStore,
private val factory: Factory
) {}
第二个参数需要一个Factory类型的参数,这个参数由defaultFactory方法提供,下面看一下这个方法
public companion object {
internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
if (owner is HasDefaultViewModelProviderFactory)
owner.defaultViewModelProviderFactory else instance
可以看到判断owner是否继承或实现了HasDefaultViewModelProviderFactory接口,如果实现了,就使用其自己的defauleViewModelProviderFactory。
这里activity/fragment已经实现了HasDefaultViewModelProviderFactory接口,那么看一下activity/fragment自己实现的defaultViewModelProviderFactory,其实就是创建了一个SavedStateViewModelFactory。
这里看一下activiy的实现
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
代码如上,如果mDefaultFactory为null,就通过new的方式构造SavedStateViewModelFactory对象返回,不为null,就直接返回。
这里先看一下SavedStateViewModelFactory类的构造方法
public SavedStateViewModelFactory(@Nullable Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle = owner.getLifecycle();
mDefaultArgs = defaultArgs;
mApplication = application;
// 如果application不为null 获取factory
mFactory = application != null
? ViewModelProvider.AndroidViewModelFactory.getInstance(application)
: ViewModelProvider.NewInstanceFactory.getInstance();
}
注意上面的注释,如果application不为null,会获取factory,这application在activity/fragment中肯定是不为null的,所以会调用AndroidViewModelFactory.getInstance方法获取factory对象
接下来就是调用ViewModelProvider类中的get方法
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
// 根据key,先从viewModelStore中获取viewModel
var viewModel = store[key]
// 这里判断viewModel是否为null
if (modelClass.isInstance(viewModel)) {
(factory as? OnRequeryFactory)?.onRequery(viewModel)
// 不为null viewModel类型转换为需要的类型
return viewModel as T
} else {
@Suppress("ControlFlowWithEmptyBody")
if (viewModel != null) {
// TODO: log a warning.
}
}
// 这里viewModel为null 需要从factory中创建
viewModel = if (factory is KeyedFactory) {
factory.create(key, modelClass)
} else {
factory.create(modelClass)
}
// 保存到viewModelStore
store.put(key, viewModel)
return viewModel
}
从上面注释可以看出,先从viewModelStore中根据key获取viewModel对象,如果viewModel不为null,就类型转换为我们需要的viewModel类型,如果为null,就通过factory创建,这里的factory就是SavedStateViewModelFactory
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
if (isAndroidViewModel && mApplication != null) {
// 查找匹配的构造
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
// doesn't need SavedStateHandle
// 不需要SavedStateHandle
if (constructor == null) {
return mFactory.create(modelClass);
}
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
try {
T viewmodel;
if (isAndroidViewModel && mApplication != null) {
viewmodel = constructor.newInstance(mApplication, controller.getHandle());
} else {
viewmodel = constructor.newInstance(controller.getHandle());
}
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
return viewmodel;
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("An exception happened in constructor of "
+ modelClass, e.getCause());
}
}
上面代码可以知道,当构造viewModel不需要SaveStateHandle参数时,直接通过mFactory.create方法创建viewModel,这里的mFactory就是AndroidViewModelFactory
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
以上代码得知,最后通过反射创建了ViewModel的实例对象。
最后,viewModel何时销毁呢,看ComponeActivity的构造方法
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
当destory时,调用viewModelStore的clear方法
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
总结
viewModel对象在不指定viewModelFactory时由AndroidViewModelFactory通过反射的方式创建,并保存在viewModelStore中,在需要时,从viewModelStore中获取,在activity/fragment销毁时,销毁