本文从本人的《一文搞懂Android JetPack组件原理之Lifecycle、LiveData、ViewModel与源码分析技巧》拆分而来,主要采用逐类源码分析方法探寻ViewModel的原理,原文内容更加全面,欢迎收藏。
组件介绍
ViewModel是MVVM中的VM,被设计用来管理View依赖的数据,通常是持有LiveData和相关的处理逻辑。ViewModel管理的数据有一个特点,就是不会随着页面配置改变而销毁,但在页面销毁时则会正常跟着销毁。
下面的例子中,自定义了一个ViewModel,管理users这组数据,并且封装了加载users的处理逻辑。而View只需要监听users,在回调中根据users处理界面就好,这样就做到了界面和数据的分离。
public class MyViewModel extends ViewModel {
private MutableLiveData> users;
public LiveData> getUsers() {
if (users == null) {
users = new MutableLiveData>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
}
}
逐类分析
逐类分析的方式适合对一个组件不了解的情况下使用,以期快速地掌握大概原理。整个过程就是以总结类功能为目的,对组件的相关类逐个通过跳转方法进入,快速阅读并做出总结,掌握类功能定义,为以后使用其它方式进一步理解源码做好准备。下面以这个方式分析一下ViewModel的源码。
第一部分的例子中定义了一个ViewModel的子类MyViewModel,然后通过ViewModelProvider的实例方法get()获取到MyViewModel的实例。
ViewModelProvider
/**
* Creates {@code ViewModelProvider}. This will create {@code ViewModels}
* and retain them in a store of the given {@code ViewModelStoreOwner}.
*
* This method will use the
* {@link HasDefaultViewModelProviderFactory#getDefaultViewModelProviderFactory() default factory}
* if the owner implements {@link HasDefaultViewModelProviderFactory}. Otherwise, a
* {@link NewInstanceFactory} will be used.
*/
public ViewModelProvider(@NonNullViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
?((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
/**
* Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given
* {@code Factory} and retain them in the given {@code store}.
*
* @param store {@code ViewModelStore} where ViewModels will be stored.
* @param factory factory a {@code Factory} which will be used to instantiate
* new {@code ViewModels}
*/
public ViewModelProvider(@NonNullViewModelStore store, @NonNull Factory factory) {
mFactory =factory;
mViewModelStore =store;
}
从构造方法中可以看出ViewModelProvider需要ViewModelStore和Factory两个类型的成员变量才能构造处理,分别是mViewModelStore和mFactory,ComponentActivity和Fragment分别都实现了ViewModelStoreOwner和HasDefaultViewModelProviderFactory接口,所以都可以从中获取到ViewModelStore和Factory的实例。
@NonNull
@MainThread
public T get(@NonNull Class 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);
}
@MainThread
public T get(@NonNull String key, @NonNullClass modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if(modelClass.isInstance(viewModel)) {
if(mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if(viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel =((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel =mFactory.create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
get()方法首先尝试通过mViewModelStore的get()方法获取ViewModel的实例,如果没获取到则使用mFactory的create()创建实例,创建出来后则存入到mViewModelStore中。在这里mFactory就是ViewModel的构造工厂,mViewModelStore则是ViewModel的缓存管理者。
ViewModelProvider作为ViewModel的提供者,使用缓存mViewModelStore和工厂mFactory实现,第一次提供ViewModel时会通过工厂创建出来,后续则都是从缓存中拿。
ViewModelStore
public ComponentActivity() {
...
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if(event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
@NonNull
@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.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc!= null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if(mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
ViewModelStoreOwner接口getViewModelStore()的实现就是提供一个ViewModelStore实例,而ComponentActivity使用Lifecycle能力在页面销毁时调用ViewModelStore实例的clear方法,清空其中的ViewModel。
public class ViewModelStore {
private final HashMap 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) {
returnmMap.get(key);
}
Set 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();
}
}
ViewModelStore中使用HashMap管理ViewModel缓存,它被页面持有,并在页面真正销毁时才清空缓存。
官网的这张图中可以说明ViewModel的生命周期。SaveStateViewModelFactory
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;
}
ComponentActivity中getDefaultViewModelProviderFactory()方法通过构造方法创建一个SavedStateViewModelFactory对象,传入了Application、当前ComponentActivity实例和Intent中的数据bundle。
SavedStateViewModelFactory构造方法
public SavedStateViewModelFactory(@NonNull Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle =owner.getLifecycle();
mDefaultArgs =defaultArgs;
mApplication =application;
mFactory =ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
构造方法接受的参数中,页面实例是SavedStateRegistryOwner接口类型的,通过该接口获取到SavedStateRegistry和Lifecycle。另外成员变量mFactory是AndroidViewModelFactory的单例对象。
SavedStateViewModelFactory的create()
@Override
public T create(@NonNull String key, @NonNullClass modelClass) {
boolean isAndroidViewModel= AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor constructor;
if(isAndroidViewModel) {
constructor =findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
constructor =findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
// doesn't need SavedStateHandle
if (constructor == null) {
returnmFactory.create(modelClass);
}
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
try {
T viewmodel;
if(isAndroidViewModel) {
viewmodel =constructor.newInstance(mApplication, controller.getHandle());
} else {
viewmodel =constructor.newInstance(controller.getHandle());
}
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
returnviewmodel;
} 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());
}
}
create()方法支持创建三种类型的ViewModel:AndroidViewModel、支持SavedState的ViewModel、普通ViewModel,这里由于篇幅原因,只分析一下普通ViewModel的创建。普通ViewModel通过mFactory的create()方法创建出来。
AndroidViewModelFactory的create()
public static class AndroidViewModelFactory extendsViewModelProvider.NewInstanceFactory {
...
@NonNull
@Override
public T create(@NonNull Class modelClass) {
if(AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
returnmodelClass.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);
}
}
AndroidViewModelFactory的create()方法判断如果不是AndroidViewModel类型,就直接通过父类的create()方法创建,而AndroidViewModelFactory的父类是NewInstanceFactory。
NewInstanceFactory的create()
public static class NewInstanceFactory implements Factory {
...
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public T create(@NonNull Class modelClass) {
//noinspection TryWithIdenticalCatches
try {
returnmodelClass.newInstance();
} catch(InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch(IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
NewInstanceFactory的create()则是直接通过反射创建出ViewModel实例。
SaveStateViewModelFactory作为ComponentActivity和Fragment提供的对象,在NewInstanceFactory的基础上增加了对AndroidViewModel和支持SavedStated的ViewModel的创建,但对于普通的ViewModel创建,最后还是降级使用NewInstanceFactory完成。
到此,ViewModel的主要类已经分析完了,接下来可以结合类关系,一定程度上总结出对全局视角的理解。
主要类说明
- ViewModelProvider:ViewModel提供者
- ViewModelStore:ViewModel缓存管理
- ViewModelProvider.Factory:ViewModel创建工厂
- SavedStateViewModelFactory:ViewModel创建工厂的实现
- NewInstanceFactory:普通ViewModel创建工厂的实现
类关系描述
ViewModel通过ViewModelProvider的get()方法获取到,ViewModelProvider由缓存ViewModelStore和创建工厂ViewModelProvider.Factory组合而成,ViewModelStore和ViewModelProvider.Factory也是ComponentActivity的一部分,ComponentActivity通过实现ViewModelStoreOwner和HasDefaultViewModelProviderFactory两个接口对外提供ViewModelStore和ViewModelProvider.Factory。其中,ViewModelProvider.Factory在ComponentActivity的具体实现是SavedStateViewModelFactory,SavedStateViewModelFactory一部分由AndroidViewModelFactory组合而成,它提供创建三种ViewModel的能力,其中普通ViewModel的创建是由AndroidViewModelFactory的父类NewInstanceFactory完成。
逐类分析方法总结
逐类分析重点在于抓大放小,分析每个类的主要目的是掌握该类的功能定位,达到目的即可,不要深陷到源码细节中。在快速分析完后,结合相关的类做出总结,从而获得整体上的了解,为以后进一步源码原理分析打好基础。
参考资料
《一文搞懂Android JetPack组件原理之Lifecycle、LiveData、ViewModel与源码分析技巧》