Viewmodel
一.什么是viewmodel
ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
二.viewmodel的引入
1.Activity在配置发生更改重新创建时,需要恢复activity原本的数据。若只有个别数据,我们可以通过onSaveInstanceState() 捆绑的bundle 恢复其数据,但是activity原本数据非常庞大,那还是用此办法的,会显的actiivty过于臃肿
2.UI controler 管理异步调用等资源清理,避免 潜在的内存泄漏,维护工作繁重
三.viewmodel的生命周期
借用官网图片
我们可以看到,viewmodel的生命周期略比activity的长
四.viewmodel 实例
1.定义一个类继承viewmodel
public class HomeViewModel extends ViewModel {
private MutableLiveData<String> mText;
public HomeViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is home fragment");
}
public LiveData<String> getText() {
return mText;
}
}
2.activity 或者frament中
HomeViewModel homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
//ui更新
}
});
所以viewmodel也是activity与framnet,fragment间通讯的利器
五.源码解析
显而易见,源码入口
ViewModelProviders.of(this).get();
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
.此处得到一个 factory 实例 ,目的 就是用来创建viewmodel 实例的。通过get()方法创建:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> 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);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//获取viewmodel
ViewModel viewModel = mViewModelStore.get(key);
//如果是当前传过来的viewmodel 则返回此viewmodel
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//创建viewmodel
//mFactory就是通过new viewmodelStore()传过来的
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
//存储viewmodel
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
可以看到我们的viewmodel在创建之后会存储到viewmodelStore中。
而在之前我们在of()方法中创建viewmodelProvider实例的时候 传了一个viewmodelStroe,下面
看看她又是怎么创建的?
@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;
}
保存activity状态
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
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;
}
可以看到 onRetainNonConfigurationInstance 方法中将viewmodel 保存到activity配置信息中,通过getLastNonConfigurationInstance获取。此处也就是为什么我们使用viewmodel时,activity屏幕旋转重建是数据不会消失的原因。
viewmodelstore就是一个存储类,内部有一个hashMap 来存储viewmodel
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();
}
}
可以看到有一个clear() 方法,用来资源回收。
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) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
因为我们的actiivty的最终父类是ComponentActivity,她又实现了LifecycleOwner 接口,
在此可感知到activity的生命周期,在页面销毁是 进行资源回收。