關於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

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