移动架构45_ViewModel管理页面数据

Android移动架构汇总​​​​​​​

文章目录

    • 1 什么是ViewModel
    • 2 ViewModel生命周期
    • 3 ViewModel实现数据共享
    • 4 原理

1 什么是ViewModel

ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类可在发生屏幕旋转等配置更改后让数据继续留存。

//Activity或者Fragment中获取对象
ViewModelProviders.of(this).get(ListBjsViewModel.class);

2 ViewModel生命周期

传入相同Activity相同,获取的实例相同
注意:不能将View传给ViewModel,否则会引起内存泄露,因为ViewModel的生命周期比Activity长

3 ViewModel实现数据共享

需求场景:两个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对象,此种方式不能用来实现数据共享功能。

4 原理

创建的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并不能达到数据持久化的目的。

你可能感兴趣的:(Android移动架构,ViewModel,MVVM,JetPack,Fragment数据共享)