ViewModel是怎么实现配置发生改变时其里面的数据不会改变?

我们都知道在配置更改期间,Activity或Fragment会进行重建,但ViewModel中的数据去不会丢失,还是会保留上次的数据。那么问题来了这是怎么实现的了?

我们可以先来回忆一下我们是怎么创建ViewModel的:

CategoriesViewModel mViewModel = new ViewModelProvider(this).get(CategoriesViewModel.class);

我们一般是 ViewModelProvider来创造的,this可以为Activity和Fragment的上下文。那么这个方法有什么问题呢?我们来看下ViewModelProvider的构造方法。

public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

可以看到这里通过owner.getViewModelStore()来得到ViewModelStore。当owner是Activity时,我们可以在Acitivity的子类ComponentActivity中找到这个方法的实现:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {
        // Lazily recreated from NonConfigurationInstances by getViewModelStore()
    private ViewModelStore mViewModelStore;

	@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;
    }

        }

在ComponentActivity中有一个ViewModelStore的参数,这个类是用来存储ViewModel的。接着我们看下getViewModelStore的方法,其中的getLastNonConfigurationInstance()其实是用来获取当活动由于一些配置改变而重建时保存下来的数据。ComponentActivity中的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;

看到了吗?这里很清楚的可以发现它保存了自己的viewModelStore参数。这样就能使即使活动重建了,活动中的viewModelStore仍然会是重建前的那一个。

现在我们已经知道了在活动重建时其里面的viewModelStore变量并不会改变。我们回到最初创造ViewModelProvider的方法中:

//ViewModelProvider
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

现在就可以很容易知道了,当我们创建ViewModelProvider时,会直接将传入的ViewModelStoreOwner(Activity,Fragment都有继承ViewModelStoreOwner的接口)的viewModelStoreOwner赋值给ViewModelProvider中的mViewModelStore。然后再调用其中的get

	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 = 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);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

get方法会从mViweModelStore中寻找是否已经有存在的ViewModel否则就会直接创造一个然后再存入mViewModelStore;

总结
Activity重建时会保存自己的ViewModelStore的数据,ViewModelStore中有所有的以当前Activity为参数创建的ViewModel对象。而ViweModelProvider中初始化后会持有Activity中viewModelStore的引用,于是就会得到销毁前的ViewModel对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值