Jetpack 源碼分析(三) - ViewModel源碼分析

??最初,我認為ViewModel的原理是非常簡單,包括網絡上有很多相關的源碼分析的文章都是這么認為。但是當我再一次認認真真的官方文檔之后,才知道ViewModel涉及到的東西遠不及我們所知道的那些。
??眾所周知,ViewModel保存的數據,在配置更改之后依然也是存在的。但是這就是引出了一個問題,ViewModelonSaveIntanceState方法有什么區別?因為我們都知道onSaveIntanceState方法就是用來保存和恢復UI的狀態和數據的。這個是本文分析的一個重點。
??同時,ViewModel只會保存因為配置更改導致Activity重建相關的數據,并不能保存因為Activity退到后臺,因資源限制(比如內存限制,電量限制等)導致被殺掉之前的數據--這就是onSaveIntanceState方法干的事。但是如果我們想要ViewModel能夠擁有這部分的能力,又應該怎么辦呢?這就設計到SavedStateHandle,這也是本文就要分析的一個重點。特別注意的是,我大概看了一下網絡上相關的資料,發現在關于這部分的資料特別的少,大家似乎都不太重視這一塊知識,但是我認為這一塊的知識特別有必要介紹一下,所以本文會花費很多的筆墨分析它。
??本文參考資料:

  1. ViewModel 概覽
  2. ViewModel 的已保存狀態模塊
  3. ViewModels : A Simple Example
  4. ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders
  5. Architecture SavedStateHandle — the ViewModel’s complement
  6. Android ViewModels: State persistence — SavedState

??注意:本文ViewModel相關源碼均是2.2.0版本。

1. 概述

??按照老規矩,我們先來介紹我們對ViewModel已有的認識吧。在MVVM中,我們都知道ViewModel承擔著一個重要角色--數據持有者。這個怎么來理解呢?我們用一個具體的場景來看看。
??假設一個Activity界面有一個RecyclerView正在展示,同時RecyclerView的數據是從服務端請求過來的。當我們的手機第一次進入這個界面,手機是豎屏的,數據正常的請求,RecyclerView拿到數據也正常的展示。但是此時,如果我此時將手機橫屏的話,會怎么樣呢?會經歷如下幾個過程:

  1. 原來的Activity對象正常的走生命周期進行銷毀。
  2. 新的Activity會被創建,同時生命周期也會走到onResume。
  3. 數據的恢復。如果我們沒有使用ViewModel用來存儲數據,那么就會重新從服務端請求數據;如果我們ViewModel來存儲數據,則不會重新請求數據,而是將豎屏前數據保存,并且成功恢復到橫屏的Activity上去。

??我們可以用官方的一張圖來簡單的描述一下這個過程:


??從這張圖里面,我們可以看出,ViewModel的生命周期要比Activity長一點。因為配置更改導致的Activity銷毀,ViewModel不會跟著銷毀,只有Activity正常finish(比如用戶點擊back退出,或者退到后臺殺掉App等),ViewModel才會銷毀。
??上面說的都是大家都知道的知識,本文會從源碼角度去分析為什么ViewModel能實現這種效果。
??同時還會介紹SavedStateHandle,這個也在前面也說過了。因為我們都知道,ViewModel不能保存Activity被系統殺掉然后重建的數據,而借助SavedStateHandle,ViewModel便能解決這個問題。說句題外話,估計是Google看到大家怨聲載道---為啥ViewModel只能保存配置更改的數據,才隨便實現這個類來滿足大家。正所謂大家苦ViewModel久矣。

2. 基本使用

??在正式分析源碼之前,我們先來看看ViewModel是怎么使用(雖然大家都比較熟悉)。首先,我們創建一個ViewModel子類,類里面有一個LiveData對象:

class MyViewModel : ViewModel() {
    val mNameLiveData = MutableLiveData<String>()
}

??然后我們在Activity里面使用它:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val textView = findViewById<TextView>(R.id.textView)
        val viewModel = ViewModelProvider(this)[MyViewModel::class.java]
        viewModel.mNameLiveData.observe(this, Observer {
            textView.text = it
        })
    }
}

??我們的例子非常簡單,這里就不過多的介紹。需要提一句的是,在最新的ViewModel中,以前通過ViewModelProviders.of方法來獲取ViewModel已經過時了,現在我們是通過ViewModelProvider方法創建ViewModel對象。通常來說,我們還需要往ViewModelProider構造方法里面傳遞一個工廠類對象,如下:

        ViewModelProvider(this, object : ViewModelProvider.Factory {
            override fun <T : ViewModel> create(modelClass: Class<T>) =
                MyViewModel() as T
        })

??當然,我們可以不帶Factory對象。那么加入Factory對象之后,相比較于以前有什么好處呢?加了Factory之后,我們可以定義構造方法帶參的ViewModel。比如說,如果,我們的一個ViewModel構造方法需要帶一個id參數,那么我們可以在Factory的create方法里面創建對象直接帶進去。
??切忌,我們不要自己創建ViewModel對象,因為自己創建的對象不能保存因為配置更改導致Activity重建的數據,從而完美避開了ViewModel的優點。
??針對于ViewModel的源碼分析,本文從Factory這個切入點入手,逐步的分析ViewModel的創建和恢復。

2. ViewModel的創建

??首先,我們先來看ViewModelProivder的構造方法。ViewModelProivder有很多構造方法,不過最終都調到同一個地方:

    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

??從這個方法中,我們看到兩個變量,mFactory就是我們預期的工廠類,用來創建ViewModel對象;mViewModelStore是一個什么東西呢?這個很好理解,mViewModelStore就是用來存儲的ViewModel對象的,比如同一個Activity的onCreate方法可能會多次回調,我們在onCreate方法初始化ViewModel的,但是不可能每次onCreate回調都會創建新的ViewModel對象,所以需要有一個東西用來存儲的我們之前創建過的ViewModel,這個就是ViewModelStore的作用。同時在后面的內容,ViewModel生命周期比Activity的生命周期長也是因為這個類。
??那么mViewModelStore對象是從哪里傳過來,我們清楚的記得構造方法里面我們并沒有傳這個變量。

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }

??我們可以看到從ViewModelStoreOwner獲取的,那么那么些類是這個借口的實現類呢?從類圖上來看,我們熟悉的ComponentActivity和Fragment實現了這個接口(這里我說的都是androidX包下)。這里,先不對ViewModelStoreOwner進行展開,后面在分析ViewModel的恢復會詳細的講解。
??總之,上面兩個變量都非常的重要。
??我們再來看一下get方法,因為真正獲取ViewModel對象就是通過這個方法的。

    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

??這個get方法沒有做什么事情,構造了一個默認的key,然后調用另一個get方法。我們來看看:

    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

??這個get方法總的來說,主要分為以下2個過程:

  1. 先通過key從ViewModelStore(緩存)獲取ViewModel對象,如果緩存中存在,直接返回。Activity經過橫屏重建之后,返回ViewMode的對象l就是這里返回。
  2. 如果緩存不存在,那么通過Factory創建一個對象,然后放在緩存中,最后返回。

??默認的Facotry,我們這里不用過多的解釋,就是簡單的調用create方法創建ViewModel對象。那么那個OnRequeryFactoryKeyedFactory又是一個什么東西呢?KeyedFactory跟默認的Facotry比較,其實就是create方法多了一個參數,這個不用過多的糾結。
??這里的核心是OnRequeryFactory,我們發現,當ViewModel是從ViewModelStore獲取的,就是回調一次OnRequeryFactoryonRequery方法。這里回調onRequery方法有什么作用呢?這個設計到后面的SavedStateHandle,我們都知道當Activity因為資源限制被系統殺掉之后重新創建會恢復之前的狀態,這里的onRequery方法的作用就是--為在這中情況能保存數據做做準備(往SavedStateRegistry里面注冊SavedStateProvider)。那么可能有人就要問了ViewModel沒有從緩存獲取ViewModel,為啥不回調onRequery方法呢?我想說的是,注冊最后都是要做的是,只是做工作可能不太一樣,所以看不到onRequery方法的回調。這里,我先粗略描述一下,后面的內容會詳細的分析這一塊的內容,大家先對此有一個印象就行。

3. ViewModel的恢復

??在前面的概述中,我們已經知道ViewModel的生命周期要比Activity長一點。那ViewModel是怎么做到的呢?對于這個問題,我猜大家首先想到的是緩存,并且這個緩存是被static關鍵字修飾的。正常來說,這個實現方案是沒有問題的,我們也能找到具體的例子,比如Eventbus就是這么實現的。
??那么在ViewModel中,這個是怎么實現的呢?我們都知道ViewModel是從一個ViewModelStore緩存里面的獲取,我們看了ViewModelStore的源碼,發現它的內部并沒有通過靜態緩存實現。那么它是怎么實現Activity在onDestroy之后(重建),還繼續保留已有的對象呢?
??這個我們可以從ComponentActivitygetViewModelStore方法去尋找答案:

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

??getViewModeStrore方法的目的很簡單,就是獲取一個ViewModelStrore對象。那么這個ViewModelStore可以從哪里獲取呢?我們從上面的代碼中可以找到兩個地方:

  1. 從NonConfigurationInstances獲取。
  2. 創建一個新的ViewModelStore對象。

??第二點我們不用看,關鍵是NonConfigurationInstances。NonConfigurationInstances這是什么東西?這里,我簡單解釋一下NonConfigurationInstances

NonConfigurationInstances其實就是一個Wrapper,用來包裝一下因為不受配置更改影響的數據,包括我們非常熟悉的Fragment,比如說,一個Activity上面有一個Fragment,旋轉了屏幕導致Activity重新創建,此時Activity跟之前的不是同一個對象,但是Fragment卻是同一個。這就是通過NonConfigurationInstances實現的(有興趣的同學可以了解一下Fragment這個case,還挺重要的,這里就不解釋了。)。

??上面說的內容看上去跟我們想要的效果挺像的。是的,ViewModelStore在Activity重建前后能保持同一個對象就是通過NonConfigurationInstances實現的。也就是說在getViewModelStore方法里面,從NonConfigurationInstances獲取的ViewModelStore對象其實就是上一個Activity的。同時,我們還可以在ComponentActivity里面看到一段代碼:

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

??從上面的代碼中,我們可以到如果Activity是因為配置更改導致onDestroy方法的回調,并不會清空ViewModelStore里面的內容,這就能保證當Activity因為配置更改導致重建重新創建的ViewModel對象跟之前創建的對象是同一個。反之,如果Activity是正常銷毀的話,則不會保存之前創建的ViewModel對象,對應的是ViewModelStore的clear方法調用。其實這個clear方法還跟kotlin里面的協程有關,這里就不過多解釋了,有興趣的同學可以看看ViewModel.viewModelScope。
??現在我們來看一下NonConfigurationInstances為啥能保證Activity重建前后,ViewModeStore是同一個對象呢?主要滿足大家的好奇心。
??我們直接從ActivityThreadperformDestroyActivity方法去尋找答案(是不是很慌)。我們知道,performDestroyActivity方法最后會回調到Activity的onDestroy方法,我們可以通過這個方法可以找到ActivtyThread在Activity onDestroy之前做了保存操作。

    ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance, String reason) {
        // ······
        performPauseActivityIfNeeded(r, "destroy");
        // Activity的onStop方法回調
        if (!r.stopped) {
            callActivityOnStop(r, false /* saveState */, "destroy");
        }
        if (getNonConfigInstance) {
            // ······
            // retainNonConfigurationInstances方法的作用就是創建一個對象
            r.lastNonConfigurationInstances= r.activity.retainNonConfigurationInstances();
            // ······
        }
        // ······
        // Activity的onDestroy方法回調
        mInstrumentation.callActivityOnDestroy(r.activity);
        // ······
        return r;
    }

??從上面的代碼中,我們可以看到,在Activity的onStop和onDestroy之間,會回調retainNonConfigurationInstances方法,同時記錄到ActivityClientRecord中去。這里retainNonConfigurationInstances方法返回的對象就是我們之前看到的NonConfigurationInstances對象。
??那么又在哪里恢復已保存的NonConfigurationInstances對象呢?這個可以從performLaunchActivity方法找到答案。performLaunchActivity方法的作用就是啟動一個Activity,Activity重建肯定會調用這個方法。在performLaunchActivity方法里面,調用了Activity的attach方法,在這個方法,Google將已有的NonConfigurationInstances賦值給了新的Activity對象。
??到這里,我們就知道為啥NonConfigurationInstances能保證ViewModelStore在Activity重建前后是同一個對象,同時也知道為啥ViewModel的生命周期比Activity的生命周期要長一點。這里我先不總結,為了方便大家理解,最后我會統一的總結。

4. SavedStateHandle

??通過前面的內容,我們可以知道ViewModel保存和恢復的數據范圍僅限于配置更改導致的重建,并不支持因為資源限制導致Activity重建(或許不應該稱為重建?)的情況。但是,大家對此的呼聲卻從來沒有停歇,Google因此新增了一個SavedStateHandle類,用來滿足我們的要求。
??在正式介紹SavedStateHandle之前,我們先看看onSaveInstanceStateViewModel之間的區別。

(1). onSaveInstanceState和ViewModel的區別

??我們先來看看onSaveInstanceState:

  1. onSaveInstanceState方法能保存的數據的場景:1. 由于資源限制,Activity被系統殺掉;2. 配置更改。
  2. onSaveInstanceState方法只能保存少量簡單的數據,大量和復雜數據最后不要放在onSaveInstanceState方法保存。因為onSaveInstanceState方法是通過Bundle保存數據,如果數據的量太大或者太復雜,會阻塞UI線程,從而影響Activity生命周期的執行。

??我們在來看看ViewModel:

  1. ViewModel能保存的數據的場景:配置更改。不支持由于限制導致Activity重建的場景。
  2. ViewModel支持保存大量和復雜的數據,比如說RecyclerView的data。

??從上面的內容,我們可以很明顯的看出來各自的缺點和優點。既然Google爸爸在強力推薦View層和Model層分離的原則,那么ViewModel支持限制導致Activity重建的場景就顯得尤為重要了。這不SavedStateHandle就出來了。

(2). SavedStateHandle的基本使用

??在分析SavedStateHandle源碼之前,我們先來看看SavedStateHandle是怎么使用的吧。
??首先定義一個構造方法帶SavedStateHandle參數的ViewModel:

class MyViewModelWithSaveStateHandle(private val saveStateHandle: SavedStateHandle) : ViewModel() {

    // 需要在資源限制導致重建的場景下保存的數據
    // 用LiveData暴露,不能讓外部直接通過LiveData去修改內部的值
    val mAgeLiveData: LiveData<Int> = saveStateHandle.getLiveData(KEY_AGE)

    // 普通的數據
    val mNameLiveData = MutableLiveData<String>()


    fun setAge(age: Int) {
        saveStateHandle.set(KEY_AGE, age)
    }

    companion object {
        const val KEY_AGE = "key_age";
    }
}

??其次,通過AbstractSavedStateViewModelFactory或者SavedStateViewModelFactory創建ViewModel對象:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val viewModel = ViewModelProvider(
            this,
            SavedStateViewModelFactory(application, this)
        )[MyViewModelWithSaveStateHandle::class.java]
    }
}

??如果我們的ViewModel構造方法只帶一個SavedStateHandle參數或者帶有一個Application參數和SavedStateHandle參數,可以直接使用SavedStateViewModelFactory。如果構造方法還帶有其他的參數,此時需要繼承AbstractSavedStateViewModelFactory實現我們自己的工廠類。在使用AbstractSavedStateViewModelFactory時,我們需要注意一點:create方法帶的SavedStateHandle參數一定傳遞到ViewModel里面去。
??通過上面的2步,我們就可以在ViewModel保存由于資源限制導致重建的數據。是不是很簡單呢?大家是不是如饑似渴的想要了解內部實現原理了呢?
??現在我們準備分析它的內部實現原理,為啥說是準備呢?因為在正式看SavedStateHandle之前,我們先來看看幾個東西,我們只有了解完這幾個東西,分析SavedStateHandle才不會懵逼。

(3). SavedState components

??我們先來看一下SavedState components里面幾個組件,分別是:SavedStateRegistryOwner,SavedStateRegistryControllerSavedStateRegistry,SavedStateProvider。一下子懟上來4個不明所以的類,我猜測大家多多少少都有點懵逼。在這里我先分別這4個類的作用:

  1. SavedStateRegistryOwner:一個接口,有一個getSavedStateRegistry方法,作用是提供SavedStateRegistry對象。該接口主要實現類有Activity和Fragment。
  2. SavedStateRegistryController:SavedStateRegistry的控制類,主要有兩個方法:performRestore方法的作用恢復數據;performSave方法主要保存數據。Activity和Fragment直接操作類就是該類。
  3. SavedStateRegistry: 主要是從UI控制器(Activity或者Fragment等)恢復數據,或者需要保存的數據寫入UI控制器的Bundle里面;外部可以通過registerSavedStateProvider方法注冊SavedStateProvider,這樣SavedStateRegistry在保存數據會SavedStateProvider提供的數據。SavedStateRegistryController主要操作類就是該類。
  4. SavedStateProvider: 主要是提供保存和恢復的數據。該接口只有一個saveState方法,主要的作用將需要保存的數據用Bundle包裝起來。

??可以用一張圖來描述他們之間的關系:


??對這4個類有了大概的認識之后,我們就從源碼的角度來看看這個4個類是怎么工作。首先我們來看看ComponentActivity:


public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {

    private final SavedStateRegistryController mSavedStateRegistryController =
            SavedStateRegistryController.create(this);
    // ······
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSavedStateRegistryController.performRestore(savedInstanceState);
        // ······
    }

    @CallSuper
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        // ······
        mSavedStateRegistryController.performSave(outState);
    }
    // ······
}

??我們從ComponentActivity源碼可以看出來,SavedStateRegistryController主要分為兩個過程:

  1. 在onCreate方法調用了performRestore方法,主要的作用是恢復已保存的數據。
  2. 在onDestroy方法調用了performSave方法,主要的作用保存數據。

??因此,我們也分為兩個過程來分析,分別從保存數據和恢復和數據來分析。

(A). 保存數據

??SvedStateRegistryController的performSave方法做什么,只是調用了SavedStateRegistry的performSave方法。我們直接看SavedStateRegistry的performSave方法:

    void performSave(@NonNull Bundle outBundle) {
        Bundle components = new Bundle();
        if (mRestoredState != null) {
            components.putAll(mRestoredState);
        }
        for (Iterator<Map.Entry<String, SavedStateProvider>> it =
                mComponents.iteratorWithAdditions(); it.hasNext(); ) {
            Map.Entry<String, SavedStateProvider> entry1 = it.next();
            components.putBundle(entry1.getKey(), entry1.getValue().saveState());
        }
        outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
    }

??performSave方法里面主要做了三件事:

  1. 如果mRestoredState不為空,表示之前恢復的數據還沒有被消費完,需要將沒有消費的數據再一次保存。
  2. 遍歷所有注冊的SavedStateProvider,將所有的SavedStateProvider提供的數據保存起來。
  3. 將所有保存的數據全部寫入到Activity的Bundle對象。注意:outBundle是Activity需要保存的數據Bundle。

??保存的數據過程還是比較簡單的,我們再來看看恢復數據的過程。

(B). 恢復數據

??我們先來看看SvedStateRegistryControllerperformRestore方法:

    public void performRestore(@Nullable Bundle savedState) {
        Lifecycle lifecycle = mOwner.getLifecycle();
        if (lifecycle.getCurrentState() != Lifecycle.State.INITIALIZED) {
            throw new IllegalStateException("Restarter must be created only during "
                    + "owner's initialization stage");
        }
        lifecycle.addObserver(new Recreator(mOwner));
        mRegistry.performRestore(lifecycle, savedState);
    }

??相比于performSave方法,performRestore多了一些操作。但是我們不需要去關心,我們的重點還是應該放在SavedStateRegistryperformRestore方法:

    void performRestore(@NonNull Lifecycle lifecycle, @Nullable Bundle savedState) {
        if (mRestored) {
            throw new IllegalStateException("SavedStateRegistry was already restored.");
        }
        if (savedState != null) {
            mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
        }

        lifecycle.addObserver(new GenericLifecycleObserver() {
            @Override
            public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_START) {
                    mAllowingSavingState = true;
                } else if (event == Lifecycle.Event.ON_STOP) {
                    mAllowingSavingState = false;
                }
            }
        });

        mRestored = true;
    }

??SavedStateRegistryperformRestore方法做的操作從savedState獲取之前保存的數據,然后賦值給mRestoredState。到這里,我們可能有疑問了?這里恢復數據只看到獲取之前數據,但是沒看到賦值到ViewModel。
??其實SavedStateRegistry里面還有一個方法,我們一直沒看--consumeRestoredStateForKey方法。我們來看看它的實現:

    public Bundle consumeRestoredStateForKey(@NonNull String key) {
        if (!mRestored) {
            throw new IllegalStateException("You can consumeRestoredStateForKey "
                    + "only after super.onCreate of corresponding component");
        }
        if (mRestoredState != null) {
            Bundle result = mRestoredState.getBundle(key);
            mRestoredState.remove(key);
            if (mRestoredState.isEmpty()) {
                mRestoredState = null;
            }
            return result;
        }
        return null;
    }

??consumeRestoredStateForKey方法的作用就是通過key從mRestoredState獲取保存的數據。是不是看到一點苗頭了?不錯,外部類就是通過該方法來獲取之前保存的數據。

(4). SavedStateViewModelFactory

??在看了4個類的實現之后,我們現在回過頭來看看SavedStateViewModelFactory在創建ViewModel做了哪些操作。我們直接看create方法:

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor<T> constructor;
        if (isAndroidViewModel) {
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }
        // doesn't need SavedStateHandle
        if (constructor == null) {
            return mFactory.create(modelClass);
        }

        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            if (isAndroidViewModel) {
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
            return viewmodel;
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to access " + modelClass, e);
        } catch (InstantiationException e) {
            throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("An exception happened in constructor of "
                    + modelClass, e.getCause());
        }
    }

??在create方法中,我們需要注意兩點:

  1. 通過SavedStateHandleController的create方法創建了一個對象。在這個方法中,我們能找到很多的問題答案,比如說將已保存的數據恢復到SavedStateHandle、向SavedStateRegistry中注冊SavedStateProivder以保證能成功保存數據。
  2. 通過反射創建ViewModel的對象。從這里,我們可以知道為啥SavedStateViewModelFactory的使用受限于ViewModel構造方法了。同時從反射中可以出來,將已有數據的SavedStateHandle傳遞到ViewModel。這就是能解釋ViewModel為啥加一個參數,就是保存資源限制導致重建的數據的原因。

??我們再來看看SavedStateHandleController的create方法:

    static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
            String key, Bundle defaultArgs) {
        Bundle restoredState = registry.consumeRestoredStateForKey(key);
        SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
        SavedStateHandleController controller = new SavedStateHandleController(key, handle);
        controller.attachToLifecycle(registry, lifecycle);
        tryToAddRecreator(registry, lifecycle);
        return controller;
    }

??create方法主要創建一個SavedStateHandleController對象,除了創建對象之外,還做了其他幾件事:

  1. 調用consumeRestoredStateForKey方法,獲取之前已保存的數據。并且將獲取的數據創建一個SavedStateHandle,以供ViewModel使用。
  2. 調用attachToLifecycle。這里做的操作主要是將SavedStateHandleSavedStateProvider注冊到SavedStateRegistry里面,以保證以下保存數據的時機能成功SavedStateHandle所支持的數據。

??到此,我們將SavedStateHandle里面一個數據者,它內部持有的數據主要是從保存和恢復的,這也是為啥ViewModel需要保存和恢復的數據要通過SavedStateHandle來初始化。

5. 總結

??到此為止,ViewModel相關分析就結束了。在這里,我對本文做一個簡單的總結。

  1. ViewModel 和 onSaveInstaceState方法區別在于:ViewModel只能保存因為配置更改導致重建的數據,但是它能保存大量和復雜的數據;onSaveInstaceState能保存配置更改導致重建和資源限制導致重建的數據,但是它只能保存少量簡單的數據。ViewModel使用SavedStateHandle能夠保存資源限制導致重建的數據。
  2. ViewModel的生命周期之所以比Activity的生命周期生命周期,主要重建之后的Activity用的是之前的ViewStore。ViewModelStore保存的是之前的ViewModel,而ViewStore在配置更改導致重建不會清空已有ViewModel。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。