Android移动架构汇总
ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类可在发生屏幕旋转等配置更改后让数据继续留存。
//Activity或者Fragment中获取对象
ViewModelProviders.of(this).get(ListBjsViewModel.class);
传入相同Activity相同,获取的实例相同
注意:不能将View传给ViewModel,否则会引起内存泄露,因为ViewModel的生命周期比Activity长
需求场景:两个Fragment之间有通信的需求,假设现在有AFragment和BFragment,当AFragment内容修改比如进行登录或者滑动了一段距离,BFragment此时需要同步数据
在ViewModel中创建一个currentPosition变量,用于记录当前选中的位置,并提供设置变量的方法以供外部Fragment调用,ViewModel的主要代码如下:
AFragment
MyViewModel myViewModel= ViewModelProviders.of(getActivity()).get(MyViewModel.class);
myViewModel.setLoginState(LoginPT);
BFragment
MyViewModel myViewModel= ViewModelProviders.of(getActivity()).get(MyViewModel.class);
int state = myViewModel.getLoginState();
在Fragment中通过ViewModelProvider获取ViewModel对象时,如果参数是requireActivity(),则获取的是宿主Activity对应的ViewModel对象。此种获取方式可以用来实现数据共享。如果参数是this,则获取的是Fragment各自对应的ViewModel对象,此种方式不能用来实现数据共享功能。
创建的ViewModel对象都会被存在ViewModelStore中,如果创建的ViewModel对象已存在,则直接取出对象并返回,如果不存在则新建。
ViewModelProvider(this)中this的参数类型是ViewModelStoreOwner,由于在androidx.activity.ComponentActivity中实现了ViewModelStoreOwner接口并实现了getViewModelStore方法,因此开发者可以直接使用当前Activity的上下文this,主要代码如下:
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ViewModelStoreOwner{
...
@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.");
}
ensureViewModelStore();
return mViewModelStore;
}
来看getViewModelStore方法,此方法会进入ensureViewModelStore方法中,ensureViewModelStore方法的代码如下:
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
这里通过(NonConfigurationInstances) getLastNonConfigurationInstance()方法来获取上一次的配置信息,NonConfigurationInstances中有viewModelStore对象,代码如下:
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
如果上一次配置信息不为空,就直接使用上一次的viewModelStore,如果为空则新建viewModelStore。在Activity旋转屏幕被销毁的时候,不仅会调用onSaveInstance-State方法,而且会调用onRetainNonConfigurationInstance方法,onRetainNonConfiguration-Instance方法的代码如下:
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
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方法中对viewModelStore进行了存储。当屏幕旋转恢复的时候会通过getLastNonConfigurationInstance方法进行恢复。getLastNonConfigurationInstance方法的代码如下:
Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationIn
tances != null
? mLastNonConfigurationInstances.activity : null;
}
所以在Activity旋转屏幕的整个过程中,ViewModelStore对象保留了下来,通过ViewModelProvider(this).get方法获取到的是同一个ViewModel实例,从而避免了由于屏幕旋转而导致数据丢失的问题
ViewModel不能数据持久化,当Activity被真正销毁的时候,ViewModel会将资源进行回收,示例代码如下:
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();
}
}
}
});
当对应的Activity被真正销毁,viewModelStore将会调用clear方法清理数据,所以ViewModel并不能达到数据持久化的目的。