关于ViewModel的一系列问题总结

作者: 奔跑吧李博 | 来源:发表于2022-12-29 12:54 被阅读0次
    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

    相关文章

      网友评论

        本文标题:关于ViewModel的一系列问题总结

        本文链接:https://www.haomeiwen.com/subject/ssjadltx.html