MVVM架构中,会用到ViewModel类,那么这个类原理是什么呢?有什么好处呢?
第一部分:源码文档解析
/**
* ViewModel is a class that is responsible for preparing and managing the data for
* an {@link android.app.Activity Activity} or a {@link androidx.fragment.app.Fragment Fragment}.
//viewmodel类是用来在activity或fragment中获取和处理数据的类
* It also handles the communication of the Activity / Fragment with the rest of the application
//他也可以用来处理activity或fragment和应用其他模块的通信
* (e.g. calling the business logic classes).
* <p>
* A ViewModel is always created in association with a scope (a fragment or an activity) and will
* be retained as long as the scope is alive. E.g. if it is an Activity, until it is
* finished.
* <p>
//viewmodel随着宿主的创建而创建,而且只要宿主还在他就会活着
* In other words, this means that a ViewModel will not be destroyed if its owner is destroyed for a
* configuration change (e.g. rotation). The new owner instance just re-connects to the existing model.
* <p>
//也就是说,这也就是如果宿主死了他不会跟着死的,例如activity的配置更改后重新创建,但是他还是原来的。
* The purpose of the ViewModel is to acquire and keep the information that is necessary for an
* Activity or a Fragment. The Activity or the Fragment should be able to observe changes in the
* ViewModel. ViewModels usually expose this information via {@link LiveData} or Android Data
* Binding. You can also use any observability construct from you favorite framework.
* <p>
//设计viewmodel的目的是获得和保持activity或fragment中的信息。宿主fragment/activity也应该观察viewmodel中数据的改变。viewmodel通常配合着databinding使用,你也可以使用其他具有观察特性的控件一起使用。
* ViewModel's only responsibility is to manage the data for the UI. It <b>should never</b> access
* your view hierarchy or hold a reference back to the Activity or the Fragment.
* <p>
//viewmodel仅仅用来管理更新UI的数据,而不应该持有view或者宿主的引用。
* Typical usage from an Activity standpoint would be:
* <pre>
//使用示例如下:
* public class UserActivity extends Activity {
*
* {@literal @}Override
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* setContentView(R.layout.user_activity_layout);
* final UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);
* viewModel.getUser().observe(this, new Observer<User>() {
* {@literal @}Override
* public void onChanged(@Nullable User data) {
* // update ui.
* }
* });
* findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
* {@literal @}Override
* public void onClick(View v) {
* viewModel.doAction();
* }
* });
* }
* }
* </pre>
*
* ViewModel would be:
* <pre>
* public class UserModel extends ViewModel {
* private final MutableLiveData<User> userLiveData = new MutableLiveData<>();
*
* public LiveData<User> getUser() {
* return userLiveData;
* }
*
* public UserModel() {
* // trigger user load.
* }
*
* void doAction() {
* // depending on the action, do necessary business logic calls and update the
* // userLiveData.
* }
* }
* </pre>
*
* <p>
* ViewModels can also be used as a communication layer between different Fragments of an Activity.
//viewmodel也可以用来用在同一个activity中不同fragment之间数据交换
* Each Fragment can acquire the ViewModel using the same key via their Activity. This allows
* communication between Fragments in a de-coupled fashion such that they never need to talk to
* the other Fragment directly.
* <pre>
//每一个fragment可以通过同一个key获取到同一个viewmodel,这就实现了fragment之间的数据交换,而不是fragment之间进行数据交换。例如:
* public class MyFragment extends Fragment {
* public void onStart() {
* UserModel userModel = new ViewModelProvider(requireActivity()).get(UserModel.class);
* }
* }
* </pre>
* </>
*/
通过官方文档我可以获取如下信息:
1.viewmodel的生命周期不随着宿主的死亡而死亡
2.viewmodel 主要是用来进行数据的传递更新UI,而不允许持有宿主的引用
3.viewmodel 应该配合着具有观察者模式的类一起使用,例如MutableLiveData
4.使用示例
5.viewmodel还可以作为同一个activity中不同fragment之间数据的传递,以及示例
第二部分:源码解析(上面示例用代码)
1.获取viewmodel
UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);
/**
* Creates {@code ViewModelProvider}. This will create {@code ViewModels}
* and retain them in a store of the given {@code ViewModelStoreOwner}.
* <p>
* 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(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), NewInstanceFactory.getInstance());
}
先看new ViewModelProvider(this):
参数为this(例如activity /fragment),那么是任何类都可以吗?不是,这个构造器的参数为ViewModelStoreOwner,这是个接口
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
我们看看他的子类有哪些:
所以我们传入fragmentactivity可以,也就是如果不是这几个类,那么我们要实现这个接口才可以,我们可以看看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);
}
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();
}
}
核心代码,hashmap保存viewmodel的。
第二个参数NewInstanceFactory.getInstance()
public static class NewInstanceFactory implements Factory {
private static NewInstanceFactory sInstance;
@NonNull
static NewInstanceFactory getInstance() {
if (sInstance == null) {
sInstance = new NewInstanceFactory();
}
return sInstance;
}
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return modelClass.newInstance();
}
}
单例模式,就一个create方法,反射创建对象。
再次回顾一下两个重要点:
第一:一个hashmap保存viewmodel
第二:一个是创建viewmodel的
下面来看new ViewModelProvider(this).get(UserModel.class); get方法:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
//获取全类名
String canonicalName = modelClass.getCanonicalName();
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//hashmap中获取
ViewModel viewModel = mViewModelStore.get(key);
//获取到了,说明以前创建过,则返回
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
}
//没获取到,则创建,通过上面分析的反射创建
viewModel = mFactory.create(modelClass);
//将创建的对象保存起来
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
通过全类名在hashmap中查找,如果有则直接返回,没有则创建新的,并保存起来。所以说,我们多次调用get方法获取或者在同一个activity中不同fragment中使用new ViewModelProvider(getActivity()).get(UserModel.class) 都是获取到的同一个viewmodel。但是文档里说当activity的配置信息发生改变,activity重新创建的时候,viewmodel是不会重新创建的,可是我们看到的却是 mViewModelStore 是activity的一个属性,也就是说activity销毁的时候,他也应该被回收了,那应该随着新的activity的创建而创建新的viewmodel吧,文档写的貌似不对啊?其实文档写的没错,我们可以去activity里看看:
//activity配置发生改变是调用这个方法
public final Object onRetainNonConfigurationInstance() {
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
我们可以看到,当activity配置发生改变时,会将viewModelStore保存起来,当页面重新创建后再次获取实例时,会调用:
@NonNull
@Override
public ViewModelStore getViewModelStore() {
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();
}
}
}
会先在配置改变保存的数据里恢复数据,没有则再去创建。
后续viewmodel配合LiveData一起使用,我们后续再分析。这里就分析viewmodel的源码。