google官网 ViewModel 概览
ViewModel有两个作用:
1. 保存数据, 屏幕旋转或者其他config change引起的activity销毁。
2. fragments之间的数据共享,以及加上Live Data后可以直接通信。
ViewModel的生命周期
由下图可以看到,ViewModel的生命周期,不随屏幕旋转而消失。知道用户主动调用finish()以后,才在onDestory()以后消失。 而对于 Fragment,是在 Fragment dettached()。
引起ViewModel消失的情况如下:
1.按返回按钮
2. 从“最近使用的应用”屏幕中滑动关闭 Activity。
3. 从 Activity 向上导航。
4. 从“设置”屏幕中终止应用。
5. Activity.finish()。
6. 切换到后台。在这种情况下,系统会尽最大努力将应用进程留在内存中。但是,当用户转而去与其他应用进行互动时,系统可能会销毁该应用进程。在这种情况下,Activity 实例连同其中存储的任何状态都会一起被销毁。当用户重新启动应用时,Activity 会出乎意料地处于干净状态。
保存数据
旋转或切换到多窗口模式时, 以前是用savedInstanceState来保存和恢复UI数据的。
从ViewModel的生命周期可以看出,现在可以用ViewModel轻松实现。
在 Fragment 之间共享数据
在每一个Fragments中都可以用如下代码找到同一个view model对象。
SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
简单源码分析
ViewModel private final Map<String, Object> mBagOfTags = new HashMap<>();
ViewModelStore private final HashMap<String, ViewModel> mMap = new HashMap<>();
ViewModelProvider 通过传递class, 反射生成返回用户的viewmodel对象, 并且让Activity存储起来。
ViewModelOwner ViewModelStore getViewModelStore(); Activity实现。所以Activity持有ViewModelStore,以及一个或多个ViewModel。
ViewModel 对象存在的时间比视图或 LifecycleOwners 的特定实例存在的时间更长。所以绝不能引用View、Lifecycle 或可能存储对 Activity 上下文的引用的任何类。
ViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 永久消失:对于 Activity,是在 Activity 完成时;而对于 Fragment,是在 Fragment 分离时。
ViewModelProvider.NewInstanceFactory 创建viewmodel对象
ViewModelProvider.AndroidViewModelFactory 创建包含application 的viewmodel对象
为何在屏幕旋转时不被回收,看以下代码中if (event == Lifecycle.Event.ON_DESTROY)的情况。
public ComponentActivity() {
Lifecycle lifecycle = getLifecycle();
//noinspection ConstantConditions
if (lifecycle == null) {
throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
+ "constructor. Please make sure you are lazily constructing your Lifecycle "
+ "in the first call to getLifecycle() rather than relying on field "
+ "initialization.");
}
if (Build.VERSION.SDK_INT >= 19) {
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_STOP) {
Window window = getWindow();
final View decor = window != null ? window.peekDecorView() : null;
if (decor != null) {
decor.cancelPendingInputEvents();
}
}
}
});
}
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();
}
}
}
});
if (19 <= SDK_INT && SDK_INT <= 23) {
getLifecycle().addObserver(new ImmLeaksCleaner(this));
}
}
请注意 if (!isChangingConfigurations()) , 也就是说view model不会被清理。并且系统会自动将 ViewModel 与发生配置更改后产生的新 Activity 实例相关联。
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
使用要注意的问题:
你自定义的viewModel必须要下面的方式生产对象,否则没有效果。
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
ViewModelProvider provider = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory());
MainActivityViewModel viewModel = provider.get(MainActivityViewModel.class);
binding.setViewModel(viewModel);
}
}
因为Activity有一个保存view model对象的操作。
这是你在MainAcitivity调用的ViewModelProvider构造函数。owner就是MainActivity对象。因为super类ComponentActivity实现了ViewModelStoreOwner。
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
具体保存操作请看代码注释:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> 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); //用反射实例化你的ViewModel
} else {
viewModel = mFactory.create(modelClass);
}
mViewModelStore.put(key, viewModel); //在这里加入你的View Model
return (T) viewModel;
}
ViewModel就是这么简单,但是和Data Binding+LiveData结合后,保存数据,fragment之间通信就是很简单了。