关于ViewModel的一系列问题总结

ViewModel 为什么被设计出来,解决了什么问题

1.不会因为屏幕旋转而销毁,减少了维护状态的工作。
2.由于在作用域内单一实例的特性,使得多个fragment之间可以方便通信,并且维护同一个数据状态。
3.完善了MVVM架构,使得解耦更加纯粹。

ViewModel的销毁

activity的销毁:

public ComponentActivity() {
    getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        // 销毁ViewModel
                        getViewModelStore().clear();
                    }
                }
            }
        });
 }

最终在调用了ViewModelStore类中的clear()方法:

public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
ViewModelScope是什么?

viewModelScope 是一个 ViewModel 的 Kotlin 扩展属性。它能在ViewModel销毁时 (onCleared() 方法调用时) 退出。所以只要使用了 ViewModel,就可以使用 viewModelScope在 ViewModel 中启动各种协程,而不用担心任务泄漏。

ViewModel 是否涉及序列化与反序列化?

是不涉及的,数据不涉及跨进程通信,都是直接在当前应用进程的内存中传递。

一个 Activity 中是否支持多个 ViewModel ?

准确的说,是支持多个 key 不一致的 ViewModel 对象,因为 ViewModelStore 的本质是一个维护 Key-ViewModel 的
map 容器。

Activity横竖屏切换时为什么viewModel能保存持有的数据

在Activity实例中重写onRetainCustomNonConfigurationInstance、getLastNonConfigurationInstance方法,打印数据,当横竖屏旋转屏幕时,会打印这两个方法,一个是activity销毁时调用,一个是activity重建时调用,这两个方法是ComponentActivity透给activity可以自己实现的方法,用于给子类保存临时数据用的。

    override fun onRetainCustomNonConfigurationInstance(): Any? {
        Log.i("minfo", "onRetainCustomNonConfigurationInstance")
        return super.onRetainCustomNonConfigurationInstance()
    }

    override fun getLastNonConfigurationInstance(): Any? {
        Log.i("minfo", "getLastNonConfigurationInstance")
        return super.getLastNonConfigurationInstance()
    }

进入ComponentActivity类的方法:

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

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

    public Object onRetainCustomNonConfigurationInstance() {
        return null;
    }

横竖屏切换调用onRetainNonConfigurationInstance,获取了页面的mViewModelStore,将mViewModelStore保存到NonConfigurationInstances的实例中。

Activity类中方法:

    @Nullable
    public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }

横竖屏切换恢复时调用getLastNonConfigurationInstance,获取activity中的mLastNonConfigurationInstances实例,获取其中的viewmodelStore,赋值给activity的viewmodelstore。

为什么横竖品切换明明调用了activity的onDestroy,viewmodel却没有调用clear呢?

如果是手动销毁页面,会走viewmodel的clear方法清除数据。但是如下代码进行了判断,当activity调用destroy,如果是因为横竖屏切换,这里就不会让viewModel清除数据。

        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // Clear out the available context
                    mContextAwareHelper.clearAvailableContext();
                    // And clear the ViewModelStore
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });

参考:
https://blog.csdn.net/OneDeveloper/article/details/115049760
https://blog.csdn.net/chuhe1989/article/details/109805408

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章