Android ViewModel如何保证,它必须与同一个Activity或Fragment绑定(在屏幕旋转的情况下)?

问题描述 投票:0回答:1

我现在正在研究Android ViewModel。有一个问题一直出现在我的脑海里,那就是:ViewModel如何保证与同一个Activity或Fragment绑定(在屏幕旋转的情况下)?在屏幕旋转后,尽管我们在onCreate或onCreateView中创建了一个新的对象,ViewModel如何保证与同一个Activity或Fragment重新绑定?

有没有人有合适的答案,请告诉我。我曾试图在许多教程中找到解决方案。

先谢谢你

android android-architecture-components android-viewmodel android-mvvm
1个回答
1
投票

当一个新的实例 ViewModelProvider 创建,第一个参数是 activity.getViewModelStore() 并根据文件规定。

返回与该活动相关联的{@link ViewModelStore}。

不再支持覆盖此方法,此方法将被改为 final 在ComponentActivity的未来版本中。 @return一个{@code ViewModelStore}。 如果在Activity被附加到应用程序实例之前,即在onCreate()之前被调用,则@会引发IllegalStateException。

它返回一个 ViewModelStore 对象。那么什么是 ViewModelStore ?

/**
 * Class to store {@code ViewModels}.
 * <p>
 * An instance of {@code ViewModelStore} must be retained through configuration changes:
 * if an owner of this {@code ViewModelStore} is destroyed and recreated due to configuration
 * changes, new instance of an owner should still have the same old instance of
 * {@code ViewModelStore}.
 * <p>
 * If an owner of this {@code ViewModelStore} is destroyed and is not going to be recreated,
 * then it should call {@link #clear()} on this {@code ViewModelStore}, so {@code ViewModels} would
 * be notified that they are no longer used.
 * <p>
 * Use {@link ViewModelStoreOwner#getViewModelStore()} to retrieve a {@code ViewModelStore} for
 * activities and fragments.
 */
 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());
 }

 /**
  *  Clears internal storage and notifies ViewModels that they are no longer used.
  */
 public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.clear();
    }
    mMap.clear();
  }
}

基本上,它是一个有以下功能的类 HashMap 其关键是 DEFAULT_KEY + “:” + canonicalName 哪儿 DEFAULT_KEYandroidx.lifecycle.ViewModelProvider.DefaultKey 和价值是 ViewModel

这意味着每个活动和片段都有一个 ViewModelStore 它保留了所有声明的 ViewModels 在活动或片段中分别。

但如何 ViewModelStore 经历了方向性的变化?

在文件中 ViewModelStore 是指

如果这个{@code ViewModelStore}的所有者由于配置*的改变而被破坏和重新创建,那么所有者的新实例应该仍然拥有与*{@code ViewModelStore}相同的旧实例。

所以活动的责任是保留 ViewModelStore 在方向改变时。

如果我们回到 activity.getViewModelStore() 的实现,那么我们就会找到答案。

if (mViewModelStore == null) {
    NonConfigurationInstances nc =
        (NonConfigurationInstances) getLastNonConfigurationInstance();
    if (nc != null) {
        // Restore the ViewModelStore from NonConfigurationInstances
        mViewModelStore = nc.viewModelStore;
    }
    if (mViewModelStore == null) {
        mViewModelStore = new ViewModelStore();
    }
}

该活动通过使用名为 NonConfigurationInstances. NonConfigurationInstances 是一个静态的最终类

static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}

所以它首先检查是否已经有一个 viewmodelstore 储存在 NonConfigurationInstances 如果没有,它将创建一个新的 ViewModelStore 或返回现有的 ViewModelStore.

那为什么不 ViewModel 失忆 finish() 场景?

ViewModelStoreclear() 方法。

/**
  *  Clears internal storage and notifies ViewModels that they are no longer used.
  */
public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.onCleared();
    }
    mMap.clear();
}

所以这个 clear() 方法被调用在 onDestroy() 的活动或片段,并清除其影响。HashMap 除了在更改配置时。这里是代码。

if (mViewModelStore != null && !isChangingConfigurations) {
    mViewModelStore.clear();
}

现在你知道ViewModel如何在配置更改中生存的秘密配方了。

编码愉快...

重要的 : 我不相信拿别人的作品做学分。要让它很容易在堆栈上获得。溢出 我把文章中的所有内容都复制到了这里 Android ViewModel的奇特案例

© www.soinside.com 2019 - 2024. All rights reserved.