简体   繁体   English

ViewModel 如何在配置更改中幸存下来

[英]How ViewModel survives configuration change

I am trying to use ViewModel in my app.我正在尝试在我的应用程序中使用 ViewModel。 The question comes to my mind is How View Model survives configuration changes.我想到的问题是 View Model 如何在配置更改中幸存下来。 I read number of blog posts saying that "我读了很多博客文章说“

It will create a HolderFragment to add to your activity or your fragment, it's invisible, when the configuration changed, activity destroyed, but holder fragment is still alive它将创建一个HolderFragment以添加到您的活动或片段中,它是不可见的,当配置更改时,活动被破坏,但持有者片段仍然存在

and that make sense.But I tried to explore more on this and found out that in support library 27.1.0+ they have removed the HolderFragment with Description saying这是有道理的。但我试图对此进行更多探索,发现在支持库 27.1.0+中,他们已经删除了带有描述的 HolderFragment 说

Deprecate ViewModelStores.of() and the HolderFragment it relies on as they are no longer needed link for android.googlesource .弃用 ViewModelStores.of() 和它所依赖的 HolderFragment,因为它们不再需要android.googlesource 的链接

Now the question is How they are doing the same thing right now?现在的问题是他们现在如何做同样的事情?

ViewModels created with ViewModelProviders.of() method are stored in ViewModelStore hashmap, so the real question is how ViewModelStore is stored.使用ViewModelProviders.of()方法创建的 ViewModel 存储在ViewModelStore hashmap 中,所以真正的问题是ViewModelStore是如何存储的。

For activities, this logic is straightforward.对于活动,这个逻辑很简单。 ViewModelStore is stored using onRetainNonConfigurationInstance method: ViewModelStore使用onRetainNonConfigurationInstance方法存储:

@Override
    @Nullable
    public final Object 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;
    }

For fragments, things are a bit more complicated.对于片段,事情要复杂一些。 FragmentManagerImpl now has a field called mNonConfig : FragmentManagerImpl现在有一个名为mNonConfig的字段:

private FragmentManagerViewModel mNonConfig;

which stores a hashmap of a Fragment's UUID and a ViewModelStore .它存储 Fragment 的 UUID 和ViewModelStore的 hashmap 。

This mNonConfig field is initialized in FragmentManagerImpl#attachController method:这个mNonConfig字段在FragmentManagerImpl#attachController方法中初始化:

    public void attachController(@NonNull FragmentHostCallback host,
            @NonNull FragmentContainer container, @Nullable final Fragment parent) {
        if (mHost != null) throw new IllegalStateException("Already attached");
        mHost = host;
        mContainer = container;
        mParent = parent;
        if (mParent != null) {
            // Since the callback depends on us being the primary navigation fragment,
            // update our callback now that we have a parent so that we have the correct
            // state by default
            updateOnBackPressedCallbackEnabled();
        }
        // Set up the OnBackPressedCallback
        if (host instanceof OnBackPressedDispatcherOwner) {
            OnBackPressedDispatcherOwner dispatcherOwner = ((OnBackPressedDispatcherOwner) host);
            mOnBackPressedDispatcher = dispatcherOwner.getOnBackPressedDispatcher();
            LifecycleOwner owner = parent != null ? parent : dispatcherOwner;
            mOnBackPressedDispatcher.addCallback(owner, mOnBackPressedCallback);
        }

        // Get the FragmentManagerViewModel
        if (parent != null) {
            mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
        } else if (host instanceof ViewModelStoreOwner) {
            ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
            mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
        } else {
            mNonConfig = new FragmentManagerViewModel(false);
        }
    }

Basically, in order to retrieve a ViewModel in Activity one should call ViewModelProviders.of(this).get(SomeViewModel.class) .基本上,为了在Activity中检索ViewModel ,应该调用ViewModelProviders.of(this).get(SomeViewModel.class) Now, if we look into of it looks like below:现在,如果我们查看它of如下所示:

public static ViewModelProvider of(@NonNull FragmentActivity activity,
        @Nullable Factory factory) {
    Application application = checkApplication(activity);
    if (factory == null) {
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
    return new ViewModelProvider(activity.getViewModelStore(), factory);
}

So, the important part is this method - activity.getViewModelStore() because it returns a wrapper object ( HashMap holder) for all of your ViewModel objects and if it can survive config changes so can all of your ViewModel objects:因此,重要的部分是这个方法 - activity.getViewModelStore()因为它为所有ViewModel对象返回一个包装器 object ( HashMap持有者),如果它可以在配置更改中幸存下来,那么所有ViewModel对象也可以:

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

mViewModelStore will be either restored from NonConfigurationInstances or created from scratch. mViewModelStore将从NonConfigurationInstances恢复或从头开始创建。 Pretty much, NonConfigurationInstances is the object that survives config changes and hence is used to store the ViewModelStore .几乎, NonConfigurationInstances是 object ,它在配置更改后仍然存在,因此用于存储ViewModelStore That's why the same ViewModelStore object is returned after rotation - it's stored in the config change independent NonConfigurationInstances :这就是为什么旋转后返回相同的ViewModelStore object - 它存储在与配置更改无关的NonConfigurationInstances

If you look into onRetainNonConfigurationInstance() , you will actually that your ViewModelStore is saved there:如果您查看onRetainNonConfigurationInstance() ,您实际上会发现您的ViewModelStore保存在那里:

public final Object onRetainNonConfigurationInstance() {
    ...
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}

Also, it will be cleared only if onDestroy for a non-config change reason is called:此外,仅当出于非配置更改原因调用onDestroy时才会清除它:

...
    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();
                }
            }
        }
    });
...   

A similar trick is used for storing a ViewModel for a Fragment .类似的技巧用于存储FragmentViewModel

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何最好地实现 ViewModel(在 AndroidX 中)以便数据在配置更改后仍然存在 - How Best To Implement ViewModel( in AndroidX) So Data Survives Configuration Changes ViewModel如何在配置更改时保留 - How ViewModel is persisted on configuration change Android MVP-可在配置更改后保留的网络请求 - Android MVP - network request that survives across configuration change 如何使Architecture的PagedListAdapter不受配置更改的影响? - How to make Architecture's PagedListAdapter survives configuration changes? 连通性更改接收器在引导后还可以存活/启动吗? - Connectivity Change Receiver survives/starts after boot? Android 生命周期感知组件如何检测 ViewModel 中的配置更改 - Android How Lifecycle-Aware Components Detect Configuration Change inside ViewModel 使用 MVVM 视图模型和实时数据时,如何在配置更改后保留 RecyclerView 的滚动位置? - How to preserve scroll position of a RecyclerView after a configuration change when using MVVM viewmodel and livedata? 使用 ViewModel 更改配置后如何防止第二次重新加载数据? - How I can prevent reloading data second time after configuration change using ViewModel? Android体系结构组件:ViewModel在配置更改时返回null - Android Architecture components: ViewModel returns null on configuration change 如何更改 ViewModel 中的 MutableLiveData 值 - How change MutableLiveData value inside ViewModel
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM