1、简介和简单使用
1.1 简介
ViewModel以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续留存,保证数据的安全持久性。
如果Activity/Fragment销毁或重新创建界面,则存储在其中的任何瞬态界面相关数据都会丢失。对于简单的数据,Activity可以使用onSaveInstanceState()方法从onCreate()中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据。
另一个问题是,Activity/Fragment经常需要进行可能需要一些时间才能返回的异步调用。Activity/Fragment需要管理这些调用,并确保系统在其销毁后清理这些调用以避免潜在的内存泄漏。此项管理需要大量的维护工作,并且在重新创建对象的情况下,会造成资源的浪费,因为对象可能需要重新发出已经发出过的调用。
而ViewModel在Actiivity重建时会自动保存,可以确保数据不会丢失,并且ViewModel的生命周期比较长,ViewModel对象存在的时间范围是获取ViewModel时传递给ViewModelProvider的Lifecycle。ViewModel将一直留在内存中,直到限定其存在时间范围的Lifecycle永久消失:对于Activity,是在Activity完成时;而对于Fragment,是在Fragment分离时。
ViewModel的生命周期:
![](https://img.haomeiwen.com/i27762813/74a1bbcaa5b51043.png)
1.2 使用
创建RandomVideModel来保存数据,继承RandomVideModel。
class RandomVideModel : ViewModel() {
var num: Int = 0
}
在Activity中实例化RandomVideModel,并从中获取数据。
class VideModelActivity : AppCompatActivity() {
private lateinit var randomVideModel: RandomVideModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_vide_model)
randomVideModel = ViewModelProvider(
this,
ViewModelProvider.NewInstanceFactory()
).get(RandomVideModel::class.java)
tv_content.text = "${randomVideModel.num}"
btn_random.setOnClickListener {
tv_content.text = "${++randomVideModel.num}"
}
}
}
2、源码分析
首先看下ViewModel的源码,ViewModel代码很简单,内部用一个HashMap存储数据。
public abstract class ViewModel {
// Can't use ConcurrentHashMap, because it can lose values on old apis (see b/37042460)
@Nullable
private final Map<String, Object> mBagOfTags = new HashMap<>();
...
}
ViewModel有3个子类,AndroidViewModel、FragmentManagerViewModel、LoaderViewModel。
AndroidViewModel内部持有一个Application,可以方便使用上下文。
可以看到,是业务层Activity中ViewModel不是直接new出来的,而是通过实例化一个ViewModelProvider对象,然后调用ViewModelProvider的get方法,传入了ViewModel的class文件,所以,ViewModel是通过反射创建出来的。
ViewModelProvider的构造方法,传入两个参数,一个是ViewModelStoreOwner,一个是Factory。AppCompatActivity继承的是ComponentActivity,ComponentActivity实现了ViewModelStoreOwner接口,所以这里传this就可以。另一个参数传Factory的实现类NewInstanceFactory。
public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
owner.viewModelStore,
factory
)
接着通过this调用了构造方法ViewModelProvider(ViewModelStore,Factory),ViewModelStore就是存储ViewModel的类,里边是一个HashMap,提供了put、get、clear方法。
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());
}
//遍历HashMap,清除所有数据
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
回到业务层Activity中,调用ViewModelProvider的get方法传入了自定义ViewModel的class。
@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)
}
接着调用get(key: String, modelClass: Class<T>)。在get方法中,创建了ViewModel对象,然后将ViewModel存放到ViewModelStore中。
@Suppress("UNCHECKED_CAST")
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
var 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.
}
}
viewModel = if (factory is KeyedFactory) {
factory.create(key, modelClass)
} else {
//由于传进来的是NewInstanceFactory,会走到这里。
factory.create(modelClass)
}
//将ViewModel存放到ViewModelStore中。
store.put(key, viewModel)
return viewModel
}
由于传入的是NewInstanceFactory,所以最终调用的是Factory接口中的create(modelClass: Class<T>)。
public interface Factory {
public fun <T : ViewModel> create(modelClass: Class<T>): T
}
而具体实现在NewInstanceFactory中,NewInstanceFactory中的create方法中最终通过反射创建了ViewModel对象。
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
//通过反射创建ViewModel对象。
return modelClass.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);
}
}
来到ComponentActivity中,上面说过,ComponentActivity实现了ViewModelStoreOwner接口。
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
ViewModelStoreOwner中有一个接口方法getViewModelStore,ComponentActivity中实现了该方法。
@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;
}
调用了ensureViewModelStore去拿到ViewModelStore。
void ensureViewModelStore() {
if (mViewModelStore == null) {
//这里的NonConfigurationInstances是ComponentActivity中的静态内部类。
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
ensureViewModelStore方法中实例化了一个NonConfigurationInstances,调用了getLastNonConfigurationInstance,从NonConfigurationInstances中拿ViewModelStore。
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
而这个方法中又调用了mLastNonConfigurationInstances.activity,点进去跳转到了Activity类中的静态内部类NonConfigurationInstances。
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
这里的activity在retainNonConfigurationInstances方法中被赋值。
NonConfigurationInstances retainNonConfigurationInstances() {
//调用onRetainNonConfigurationInstance获取activity
Object activity = onRetainNonConfigurationInstance();
...
NonConfigurationInstances nci = new NonConfigurationInstances();
//赋值给NonConfigurationInstances中的activity
nci.activity = activity;
...
return nci;
}
接着来到了Activity类中的onRetainNonConfigurationInstance,该方法的具体实现在ComponentActivity类中。
Activity中的onRetainNonConfigurationInstance:
public Object onRetainNonConfigurationInstance() {
return null;
}
ComponentActivity中的onRetainNonConfigurationInstance:
public final Object onRetainNonConfigurationInstance() {
// Maintain backward compatibility.
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
到这里,业务层Activity就拿到了ViewModelStore,就可以操作ViewModel中的数据了。
而如何保证数据的稳健性不会丢失,可以看ComponentActivity的构造方法。在ComponentActivity无参构造方法中有如下代码:
public ComponentActivity() {
Lifecycle lifecycle = getLifecycle();
...
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();
}
}
}
});
}
这里对Lifecycle状态进行了监听,当状态处于ON_DESTROY,也就是页面销毁时,先判断isChangingConfigurations是否为true,为true的话,就不用调用getViewModelStore().clear(),这样就保证了ViewModel中数据的持久稳健性。
public boolean isChangingConfigurations() {
return mChangingConfigurations;
}
mChangingConfigurations的值,默认是false,但是在因为Configuration的改变被销毁了又重建的时候(最常见的就是横竖屏切换),mChangingConfigurations的值为true,ViewModelStore不调用clear,数据不会清除。这就保证了Activity销毁重建的时候数据不会丢失,还可以继续正常使用。
/** true if the activity is being destroyed in order to recreate it with a new configuration */
/*package*/ boolean mChangingConfigurations = false;
3、流程图
![](https://img.haomeiwen.com/i27762813/ed40142dfdfa52b2.png)
网友评论