作用存储和管理UI相关的数据,并且与声明周期关联。ViewModel保证数据在配置改变时能够存活,如屏幕旋转。
引入的原因
- 如果系统销毁或者重新创建UI组件,那么存储的与UI相关的瞬时数据就会丢失。举例来说,你的应用可能在Activity中存储了一个用户列表。当Activity因为配置改变重建时,新的Activity需要重新获取用户列表。针对简单的数据,Activity可以用
onSaveInstanceState()方法存储并在onCreate()重建这些数据,但是这个方法只是适用于少量的可以被序列化和反序列化的数据,而不适用于大量的数据例如用户或者位图的列表。 - 另一个问题是UI组件会经常需要异步调用,它们需要花费一些时间。UI组件需要管理这些异步调用,并且确保系统能够在组件被销毁时能够回收这些调用,以避免内存泄漏。这些管理需要大量的维护工作,同时这些对象在配置改变时会重新创建,这是一种资源浪费,因为这些对象已经创建了,但是又必须重新创建。
- 像Activity和Fragment这样的UI组件的首页目的是展示UI数据,响应用户行为,以及处理操作系统的行为,如权限申请。UI组件也需要负责从数据库或者网络加载数据,这会使类膨胀。将过多的责任分配给UI组件会导致一个类需要独立处理很多工作,而不是将这些工作委托给其他类。把过多的工作分配给UI组件也会导致测试变得困难。
使用:
定义ViewModel
public class UserViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
static class User {
String name;
int age;
}
}
在Activity中获取一个实例
UserViewModel model = null;
model = new ViewModelProvider(this).get(UserViewModel.class);
model.getUsers().observe(this, new Observer<List<UserViewModel.User>>() {
@Override
public void onChanged(List<UserViewModel.User> users) {
}
});
在多个Fragment中共享ViewModel
//通过activity的ViewModelStore获取ViewModel
new ViewModelProvider(getActivity()).get(UserViewModel.class);
类图:
关键类:
ViewModel:数据管理类,以及处理Activity和Fragment对数据的交互操作
public abstract class ViewModel {
//为ViewModel存储一些数据
private final Map<String, Object> mBagOfTags = new HashMap<>();
//onDestroy时标记数据已被清除
private volatile boolean mCleared = false;
}
ViewModelStore:存储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());
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
ViewModelProvider:获取ViewModel
public class ViewModelProvider {
//ViewModel的创建工厂
private final Factory mFactory;
//存储ViewModel
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
//获取对应的ViewModel对象
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//如果ViewModelStore中不存在,则使用Factory创建
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
}
Factory:创建ViewlMode实例
public interface Factory {
@NonNull //创建ViewModel实例
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
实现Factory接口的有KeyedFactory,NewInstanceFactory,AndroidViewModelFactory等实例创建类
Activity的重建时的数据恢复过程:
数据保存过程
-
在ComponentActivity的onSaveInstanceState()中保存:
-
SavedStateRegistryController中调用SavedStateRegistry进行保存
-
SavedStateRegistry执行保存逻辑
①AbstractSavedStateViewModelFactory创建的对象最终会被添加到mComponents中②在数据恢复时,mRestoredState会从取出保存的components。当调用AbstractSavedStateViewModelFactory的create方法时,会从mRestoredState中获取对应的bundle,并remove
如何去使用这些数据的逻辑有点复杂,可以看AbstractSavedViewModelFactory的create方法:
数据恢复过程
- ComponentActivity的onCreate执行恢复:
- SavedStateRegistryController中调用SavedStateRegistry的performRestore进行恢复:
- SavedStateRegistry执行恢复逻辑
取出保存时key为SAVED_COMPONENTS_KEY对应的bundle