深入理解AAC架構(gòu) - ViewModel 使用以及整體機(jī)制源碼

本文主要內(nèi)容:

  1. 作用介紹
  2. 核心類介紹
  3. 基本使用
  4. 源碼分析
    -- 橫豎屏切換恢復(fù)
    -- 后臺銷毀恢復(fù)

ViewModel的主要工作:

本身主要是一個數(shù)據(jù)維護(hù)工具
將數(shù)據(jù)維護(hù)的工作從Activity上剝離,提供一個儲存數(shù)據(jù)環(huán)境着绷,自身機(jī)制可以解決開發(fā)中址貌,數(shù)據(jù)受Activity生命周期影響產(chǎn)生數(shù)據(jù)丟失的問題 (主要為橫豎屏切換以及在后臺被銷毀)窘面。
通常結(jié)合LiveData使用。

官方介紹上的生命周期圖 (一般在`onCreate()`中初始化)

作為一個純數(shù)據(jù)維護(hù)工具,可以加入到MVP架構(gòu)中負(fù)責(zé)數(shù)據(jù)保存。
而官方推選作為AAC架構(gòu)MVVM中的VM層。


ViewModel的主要類:

  • ViewModel (下稱VM)
    數(shù)據(jù)儲存類刃泡,架構(gòu)的核心類。
    使用時碉怔,直接繼承該類烘贴,根據(jù)需求選擇重寫onCleared()方法。
    如需在Activity被系統(tǒng)銷毀后依然保存數(shù)據(jù)撮胧,定義一個參數(shù)為(SavedStateHandle)的構(gòu)造方法桨踪,并將數(shù)據(jù)保存SavedStateHandle中。
    實(shí)際上通過SavedInstanceState存取

  • AndroidViewModel
    VM子類趴樱,維護(hù)了Application的引用馒闷,由架構(gòu)中的SavedStateViewModelFactory創(chuàng)建時傳入。
    同樣叁征,需要接收SavedStateHandle時纳账,需要定義參數(shù)為 (Application, SavedStateHandle)的構(gòu)造方法。

  • ViewModelStore
    用于保存VM捺疼,內(nèi)部維護(hù)了一個用于儲存VMHashMap疏虫。
    一般情況下,直接使用本類創(chuàng)建實(shí)例啤呼。

  • ViewModelStoreOwner
    接口卧秘,實(shí)現(xiàn)該接口的類,表示自身能夠向外提供VM官扣。
    androidx 的AppCompatActivity/Fragment實(shí)現(xiàn)了該接口翅敌。

  • ViewModelProvider
    VM的提供者,獲取VM的基本入口惕蹄。
    實(shí)際依賴ViewModelStore存取VM蚯涮,Factory生成/恢復(fù)VM

  • Factory
    接口卖陵,實(shí)現(xiàn)該接口的類主要用于創(chuàng)建VM實(shí)例遭顶。
    不建議直接實(shí)現(xiàn)該接口,除非你清楚框架內(nèi)容和自己的需求泪蔫。
    一般情況下棒旗,如果無需SavedStateHandle機(jī)制,可以使用AndroidViewModelFactory撩荣。
    否則應(yīng)該使用或繼承SavedStateViewModelFactory铣揉。


ViewModel的基本使用:

  • 一般使用:
// VM
class ViewModelA : ViewModel()
// AVM
class ViewModelB(app: Application) : AndroidViewModel(app)

// Activity/Fragment .onCreate中
override fun onCreate() {
  ...
  val provider = ViewModelProvider(this)
  val vmA = provider.get(ViewModelA::class.java)
  val vmB = provider.get(ViewModelB::class.java)
  ...
}
  • 接受 SavedStateHandle
// VM
class ViewModelC(
        val handle: SavedStateHandle
) : ViewModel()

// AVM
class ViewModelD(
        app: Application, 
        val handle: SavedStateHandle
) : AndroidViewModel(app)
  • 跨 Fragment 共享數(shù)據(jù)
    Fragment中直接以Activity作為ViewModel的Key
...
val provider = ViewModelProvider(requireActivity())
val vmA = provider.get(ViewModelA::class.java)
  • 通過 Application 創(chuàng)建全局共享的 VM
class App : Application(), ViewModelStoreOwner {
    private lateinit var mAppViewModelStore: ViewModelStore
    private lateinit var mFactory: ViewModelProvider.Factory

    override fun onCreate() {
        super.onCreate()
        mAppViewModelStore = ViewModelStore()
        mFactory = ViewModelProvider
                      .AndroidViewModelFactory
                      .getInstance(this)
    }

    override fun getViewModelStore(): ViewModelStore {
        return mAppViewModelStore
    }

    private fun getAppFactory(): ViewModelProvider.Factory {
        return mFactory
    }

    fun getAppViewModelProvider(activity: Activity): ViewModelProvider {
        val app = checkApplication(activity) as App
        return ViewModelProvider(app, app.getAppFactory())
    }

    fun getAppViewModelProvider(fragment: Fragment): ViewModelProvider {
        return getAppViewModelProvider(fragment.requireActivity())
    }

    private fun checkApplication(activity: Activity): Application {
        return activity.application
                ?: throw IllegalStateException(
                      "Your activity is not yet attached to the Application instance." + 
                      "You can't request ViewModel before onCreate call.")
    }
}

ViewModel的關(guān)鍵源碼分析:

以下源碼分析將會去除非相關(guān)代碼以簡化

  • ViewModelProvider 實(shí)現(xiàn)相關(guān):

前面提到饶深,ViewModelProvider的工作完全依賴傳入的ViewModelStoreFactory,可以直接從構(gòu)造方法得知:

ViewModelProvider.java
----------------------

private final Factory mFactory;
private final ViewModelStore mViewModelStore;

public ViewModelProvider(ViewModelStoreOwner owner) {
  this(owner.getViewModelStore(), 
        owner instanceof HasDefaultViewModelProviderFactory
        ? ((HasDefaultViewModelProviderFactory) owner)
            .getDefaultViewModelProviderFactory()
        : NewInstanceFactory.getInstance());
}

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

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

// 簡單的反射創(chuàng)建實(shí)例的工廠
public static class NewInstanceFactory implements Factory {
    public <T extends ViewModel> T create(Class<T> modelClass) {
        return modelClass.newInstance()
    }
}

androidx.activity.ComponentActivity逛拱,androidx.fragment.app.Fragment都實(shí)現(xiàn)了ViewModelStoreOwner粥喜,HasDefaultViewModelProviderFactory接口。

public class AppCompatActivity extends FragmentActivity...{}
public class FragmentActivity extends ComponentActivity...{}

public class ComponentActivity extends ... implements
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner ... {}

public class Fragment implements 
        ViewModelStoreOwner, 
        HasDefaultViewModelProviderFactory, 
        SavedStateRegistryOwner ... {}

ViewModelProviderget()方法中返回VM實(shí)例橘券,其中mFactorySavedStateViewModelFactory

ViewModelProvider.java
----------------------

private static final String DEFAULT_KEY 
      = "androidx.lifecycle.ViewModelProvider.DefaultKey";

public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

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

    // 一個確保機(jī)制
    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        }
        return (T) viewModel;
    }

    // 正常以及基本的邏輯
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
    } else {
        viewModel = (mFactory).create(modelClass);
    }

    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}

SavedStateViewModelFactory在后面解析。


  • ViewModel 的屏幕橫豎屏切換恢復(fù)機(jī)制:

前面說到卿吐,創(chuàng)建VM是通過ViewModelProvider實(shí)現(xiàn)的旁舰,而ViewModelProvider又是依賴ViewModelStore進(jìn)行VM的保存。
當(dāng)使用ComponentActivity/Fragment作為ViewModelProvider的初始化參數(shù)時嗡官,實(shí)際VM的儲存容器是參數(shù)提供的箭窜。

  1. ComponentActivity 實(shí)現(xiàn):

從源碼中,可以看出橫豎屏切換是直接通過NonConfigurationInstances進(jìn)行恢復(fù)的衍腥。

ComponentActivity包含一個NonConfigurationInstances類磺樱,其中持有ViewModelStore的引用:

ComponentActivity.java
----------------------

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

保存ViewModelStore
通過onRetainNonConfigurationInstance()在橫豎屏切換中保存ViewModelStore

ComponentActivity.java
----------------------

public final Object onRetainNonConfigurationInstance() {
    Object custom = onRetainCustomNonConfigurationInstance();

    // 從上一個 NonConfigurationInstances 中恢復(fù) ViewModelStore
    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        NonConfigurationInstances nc = 
                (NonConfigurationInstances) getLastNonConfigurationInstance();

        if (nc != null) {
            viewModelStore = nc.viewModelStore;
        }
    }

    if (viewModelStore == null && custom == null) {
        return null;
    }
    
    // 保存當(dāng)前 ViewModelStore
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}

在使用時嘗試通過getLastNonConfigurationInstance()恢復(fù)ViewModelStore

ComponentActivity.java
----------------------

public ViewModelStore getViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc = 
                (NonConfigurationInstances) getLastNonConfigurationInstance();

        if (nc != null) {
            // 通過 NonConfigurationInstances 對象直接恢復(fù) ViewModelStore
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}
  1. Fragment 實(shí)現(xiàn):

要看懂該部分源碼,需要對FragmentManager有基礎(chǔ)了解婆咸,參考:深入理解FragmentManager

FragmentViewModelStoreFragmentManager維護(hù)的FragmentManagerViewModel管理竹捉。

  • 注意這里使用了一個VM來維護(hù)一個ViewModelStore
Fragment.java
-------------

public ViewModelStore getViewModelStore() {
    return mFragmentManager.getViewModelStore(this);
}


FragmentManager.java
--------------------

private FragmentManagerViewModel mNonConfig;

ViewModelStore getViewModelStore(Fragment f) {
    return mNonConfig.getViewModelStore(f);
}

處理FragmentManagerViewModel的實(shí)例化:

FragmentManager.java
--------------------

void attachController(FragmentHostCallback<?> host, 
                      FragmentContainer container,
                      final Fragment parent) {
    mHost = host;
    mParent = parent;

    if (parent != null) {
        // 從父類的FM中獲取
        mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
    } else if (host instanceof ViewModelStoreOwner) {
        // 假如 host 對象是實(shí)現(xiàn)了 ViewModelStoreOwner
        // 則使用這個ViewModelStoreOwner的viewModelStore創(chuàng)建一個 FragmentManagerViewModel
        ViewModelStore viewModelStore = 
                ((ViewModelStoreOwner) host).getViewModelStore();
        mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
    } else {
        // 生成一個不支持自動保存ViewModel的 FragmentManagerViewModel
        mNonConfig = new FragmentManagerViewModel(false);
    }
}

但從源碼注釋可以了解到,第三種情況已廢棄尚骄,理想情況下并不支持块差。


所以基本上,出現(xiàn)的應(yīng)該為第一倔丈、第二種情況憨闰。

host對象實(shí)際是實(shí)現(xiàn)的ViewModelStoreOwner接口的FragmentActivity$HostCallbacks

FragmentActivity.java
---------------------

class HostCallbacks 
            extends FragmentHostCallback<FragmentActivity> 
            implements ViewModelStoreOwner ... {...}

第二種情況,attachController()傳入?yún)?shù)為null需五,可以理解為直接附著在FragmentActivity上的Fragment:

FragmentActivity.java
---------------------

protected void onCreate(@Nullable Bundle savedInstanceState) {
    mFragments.attachHost(null /*parent*/);
}


FragmentController.java
-----------------------

public void attachHost(Fragment parent) {
    mHost.mFragmentManager.attachController(mHost, mHost, parent);
}

而第一種情況鹉动,attachController()傳入?yún)?shù)為Fragment,在FragmentperformAttach()中調(diào)用:

Fragment.java
-------------

void performAttach() {
    mChildFragmentManager.attachController(mHost, new FragmentContainer(), this)
}

...
解決了FragmentManagerViewModel的來源宏邮,下面看看它的作用泽示。
上文提到,FragmentManagerViewModel是一個VM蜀铲,實(shí)際上可以聯(lián)想到可能是通過ActivityViewModelStore边琉,使用相同的NonConfigurationInstances機(jī)制實(shí)現(xiàn)的恢復(fù)。

先看第二種情況:

FragmentManager.java
--------------------

ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);

其中的hostFragmentActivity$HostCallbacks记劝,而getViewModelStore()返回的實(shí)際上是FragmentActivityViewModelStore

FragmentActivity$HostCallbacks.java
-----------------------------------

public ViewModelStore getViewModelStore() {
    return FragmentActivity.this.getViewModelStore();
}

FragmentManagerViewModel.getInstance()內(nèi)部實(shí)際上是通過ViewModelProvider返回一個本類VM實(shí)例:

FragmentManagerViewModel .java
------------------------------

static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
    ViewModelProvider viewModelProvider = 
                new ViewModelProvider(viewModelStore, FACTORY);
    return viewModelProvider.get(FragmentManagerViewModel.class);
}

由于VM在創(chuàng)建時变姨,會被儲存到對應(yīng)的ViewModelStore,所以該VM會存放到FragmentActivityViewModelStore中厌丑。

第一種情況:
實(shí)際上是頂級FragmentManagerFragmentManagerViewModel中定欧,維護(hù)一個子級的FragmentManagerViewModel倉庫渔呵,然后通過頂級FragmentManagerViewModel直接維護(hù)所有子級FragmentManagerViewModel

FragmentManagerViewModel .java
------------------------------

private final HashMap<String, FragmentManagerViewModel> mChildNonConfigs = new HashMap<>();

FragmentManagerViewModel getChildNonConfig(@NonNull Fragment f) {
    FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
    if (childNonConfig == null) {
        childNonConfig = new FragmentManagerViewModel(mStateAutomaticallySaved);
        mChildNonConfigs.put(f.mWho, childNonConfig);
    }
    return childNonConfig;
}

...
從以上源碼中可以看出砍鸠,Fragment的橫豎屏切換恢復(fù)機(jī)制實(shí)際上是:

  • 通過一個持有自身ViewModelStore引用的VM扩氢,依附到ActivityViewModelStore中,通過Activity的機(jī)制進(jìn)行恢復(fù)爷辱。

其實(shí)這里引申一點(diǎn)的是录豺,源碼中提及到,NonConfigurationInstances機(jī)制有可能在調(diào)用getLastNonConfigurationInstance時返回null饭弓,如需確保橫豎屏切換時的數(shù)據(jù)保存双饥,可以使用FragmentonSaveInstanceState(true),以Fragment作為保存數(shù)據(jù)的容器弟断。


而事實(shí)上咏花,在舊版的ViewModel中,確實(shí)是通過FragmentonSaveInstanceState(true)進(jìn)行的阀趴。


  • ViewModel 的后臺銷毀恢復(fù)機(jī)制:

前文提到昏翰,SavedStateViewModelFactory是實(shí)現(xiàn)該機(jī)制的一部分,由SavedStateViewModelFactory生成的VM才具有在后臺銷毀前后通過SavedStateHandle存取數(shù)據(jù)的特性刘急。


先看SavedStateViewModelFactory的構(gòu)造方法:

SavedStateViewModelFactory.java
-------------------------------

public SavedStateViewModelFactory(Application application,
                                  SavedStateRegistryOwner owner,
                                  Bundle defaultArgs) {

    mSavedStateRegistry = owner.getSavedStateRegistry();
    mLifecycle = owner.getLifecycle();
    mDefaultArgs = defaultArgs;
    mApplication = application;
    mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}

SavedStateViewModelFactoryComponentActivity中實(shí)例化傳入的參數(shù)為:

ComponentActivity.java
----------------------

mDefaultFactory = new SavedStateViewModelFactory(
                            getApplication(), 
                            this, 
                            getIntent() != null ? getIntent().getExtras() : null);

ComponentActivity實(shí)現(xiàn)了SavedStateRegistryOwner接口棚菊,該接口的實(shí)現(xiàn)類可以提供SavedStateRegistry實(shí)例。


SavedStateRegistry即是流程的關(guān)鍵對象之一排霉。
這里涉及到androidx提供的一個新的組件androidx.savedstate:"該組件允許以插件方式窍株,將組件添加到SaveInstanceState過程中"。

個人理解:
這是一套針對SavedState操作Bundle的封裝工具攻柠,但僅適用于系統(tǒng)實(shí)現(xiàn)球订。
因?yàn)榱鞒谭爆崳到y(tǒng)源碼在實(shí)現(xiàn)的過程中還包含了自動重建瑰钮,自動還原數(shù)據(jù)冒滩,生命周期確保等一系列操作。
而且當(dāng)你實(shí)現(xiàn)關(guān)鍵的SavedStateProvider接口時浪谴,同樣要編寫B(tài)undle开睡,這和傳統(tǒng)的onSaveInstanceState()區(qū)別不大。
因?yàn)橄到y(tǒng)實(shí)現(xiàn)了對VM提供的存取操作苟耻,建議直接使用VM篇恒,或者直接在onSaveInstanceState()對數(shù)據(jù)進(jìn)行操作。

我后面有空會另行寫一篇文章去討論系統(tǒng)對該組件的實(shí)現(xiàn)凶杖。


ComponentActivity實(shí)例化時胁艰,創(chuàng)建成員SavedStateRegistryController,后者實(shí)例化時,創(chuàng)建成員SavedStateRegistry

ComponentActivity.java
----------------------

private final SavedStateRegistryController mSavedStateRegistryController =
                SavedStateRegistryController.create(this);


SavedStateRegistryController.java
---------------------------------

public static SavedStateRegistryController create(SavedStateRegistryOwner owner) {
    return new SavedStateRegistryController(owner);
}

private SavedStateRegistryController(SavedStateRegistryOwner owner) {
    mOwner = owner;
    mRegistry = new SavedStateRegistry();
}

ComponentActivityonSaveInstanceState()中調(diào)用SavedStateRegistryController.performSave()腾么,內(nèi)部實(shí)際調(diào)用SavedStateRegistry.performSave()

ComponentActivity.java
----------------------

protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mSavedStateRegistryController.performSave(outState);
}


SavedStateRegistryController.java
---------------------------------

public void performSave(Bundle outBundle) {
    mRegistry.performSave(outBundle);
}

SavedStateRegistry會把所有注冊到自身的SavedStateProvider奈梳,通過saveState()提取數(shù)據(jù),并保存到一個Bundle中:

SavedStateRegistry.java
-----------------------

void performSave(@NonNull Bundle outBundle) {
    Bundle components = new Bundle();
    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);
}

至此解虱,說明數(shù)據(jù)保存的發(fā)起攘须,最終通知到SavedStateRegistry


先看SavedStateProvider接口:

注冊到SavedStateRegistry中實(shí)現(xiàn)類殴泰,會在SavedStateRegistry保存過程將會調(diào)用saveState()獲取數(shù)據(jù)于宙。
而稍后(在恢復(fù)數(shù)據(jù)時),將會通過SavedStateRegistry.consumeRestoredStateForKey()取出保存的數(shù)據(jù)悍汛。

SavedStateRegistry$SavedStateProvider.java

SavedStateProvider通過SavedStateRegistry.registerSavedStateProvider()注冊到SavedStateRegistry

SavedStateRegistry.java
-----------------------

public void registerSavedStateProvider(String key, SavedStateProvider provider) {
    SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
    if (previous != null) {
        throw new IllegalArgumentException(
                "SavedStateProvider with the given key is already registered");
    }
}

到此限煞,說明儲存數(shù)據(jù)的提供者,是注冊到SavedStateRegistry中的SavedStateProvider员凝。


前文提及,VM的存取核心是SavedStateHandle奋献,那么說明SavedStateProviderSavedStateHandle存在必然的關(guān)聯(lián)健霹。
實(shí)際上,SavedStateHandle實(shí)例中瓶蚂,維護(hù)一個SavedStateProvider匿名內(nèi)部類實(shí)例糖埋,而SavedStateHandle的讀寫和SavedStateProvider實(shí)例的數(shù)據(jù)讀取操作,都是對實(shí)際數(shù)據(jù)容器mRegular讀寫窃这。

先看SavedStateHandle

  • 前文提到瞳别,最終該機(jī)制的實(shí)現(xiàn),實(shí)際為SaveInstanceState機(jī)制杭攻,則反映VM并不會對數(shù)據(jù)進(jìn)行自動存取祟敛。
    事實(shí)上VM確實(shí)需要手動將后臺銷毀前保存的數(shù)據(jù)放到SaveInstanceState中,SavedStateHandle確實(shí)是這么用的兆解,所以提供了一系列的get/set操作馆铁,而最終還要編寫SavedStateProviderBundle轉(zhuǎn)換操作。

  • 同時可以看出锅睛,SavedStateHandle提供了對LiveData的存取支持埠巨。
    SavedStateHandleLiveData的支持,來自對LiveData的內(nèi)部的靜態(tài)包裝類SavingStateLiveData现拒。
    SavingStateLiveData包裝了setValue()辣垒,傳入的參數(shù)會被優(yōu)先儲存到mRegular中。

用于提取數(shù)據(jù)的SavedStateProvider

需要編寫SavedStateProvider數(shù)據(jù)的Bundle轉(zhuǎn)換操作印蔬。
所以如無必要勋桶,無需自定義該組件,建議在onSaveInstanceState()中直接操作。

SavedStateHandle.java
---------------------

// 最終的數(shù)據(jù)容器主體
// initialState為構(gòu)造時參入的上次SavedInstanceState產(chǎn)生的舊數(shù)據(jù)
// 既 SavedStateHandle.createHandle 時傳入的參數(shù)哥遮,下面會說明
final Map<String, Object> mRegular = new HashMap<>(initialState);

// SavedStateProvider 對數(shù)據(jù)主體 mRegular 進(jìn)行處理并生成一個Bundle
private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
        public Bundle saveState() {
            Set<String> keySet = mRegular.keySet();
            ArrayList keys = new ArrayList(keySet.size());
            ArrayList value = new ArrayList(keys.size());
            for (String key : keySet) {
                keys.add(key);
                value.add(mRegular.get(key));
            }
            Bundle res = new Bundle();
            // "parcelable" arraylists - lol
            res.putParcelableArrayList("keys", keys);
            res.putParcelableArrayList("values", value);
            return res;
        }
};

至此岂丘,SavedStateHandleSavedStateProvider實(shí)現(xiàn)關(guān)聯(lián)。


前文提及眠饮,SavedStateProvider通過SavedStateRegistry.registerSavedStateProvider()注冊到SavedStateRegistry

而該方法的調(diào)用奥帘,則是通過SavedStateHandleController進(jìn)行的。
SavedStateHandleController的實(shí)例化則是通過SavedStateViewModelFactory進(jìn)行的仪召,最終回到了SavedStateViewModelFactory寨蹋。

先看SavedStateViewModelFactory

通過調(diào)用SavedStateHandleController.create()返回SavedStateHandleController實(shí)例。
同時扔茅,VM在創(chuàng)建時已旧,傳入了SavedStateHandleControllerSavedStateHandle實(shí)例作為參數(shù),即VMSavedStateHandle進(jìn)行了綁定召娜。

SavedStateViewModelFactory.java
-------------------------------

public <T extends ViewModel> T create(String key, Class<T> modelClass) {

    // 判斷是否是AVM
    boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
    Constructor<T> constructor;
    if (isAndroidViewModel) {
        constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
    } else {
        constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
    }

    // 如果不需要SavedStateHandle运褪,則直接創(chuàng)建一個普通的VM/AVM
    if (constructor == null) {
        return mFactory.create(modelClass);
    }

    // 創(chuàng)建了 SavedStateHandleController 
    SavedStateHandleController controller = SavedStateHandleController.create(
                                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);

    // VM 在創(chuàng)建的時候持有了SavedStateHandleController內(nèi)維護(hù)的SavedStateHandle對象
    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;
        ...
}

再看SavedStateHandleController .create()

SavedStateHandle在實(shí)例化時,通過consumeRestoredStateForKey()傳入上次保存的數(shù)據(jù)玖瘸,此時SavedStateHandle數(shù)據(jù)已完成恢復(fù)秸讹。
SavedStateHandleController創(chuàng)建后,通過attachToLifecycle()方法雅倒,在方法內(nèi)部將SavedStateHandle維護(hù)的SavedStateProvider注冊到SavedStateRegistry璃诀。

前面說到SavedStateViewModelFactory是框架骨架之一,實(shí)際就是通過這個過程蔑匣,最終允許VM能夠把數(shù)據(jù)的存取加入到SaveInstanceState流程劣欢。

SavedStateHandleController.java
-------------------------------

static SavedStateHandleController create(SavedStateRegistry registry, 
                      Lifecycle lifecycle, String key, Bundle defaultArgs) {

    // 通過consumeRestoredStateForKey獲取前次狀態(tài)
    Bundle restoredState = registry.consumeRestoredStateForKey(key);
    // 創(chuàng)建一個Handle
    SavedStateHandle handle = 
                SavedStateHandle.createHandle(restoredState, defaultArgs);

    // 生成SavedStateHandleController實(shí)例
    SavedStateHandleController controller = 
                new SavedStateHandleController(key, handle);

    // 這里進(jìn)行了綁定
    controller.attachToLifecycle(registry, lifecycle);
    tryToAddRecreator(registry, lifecycle);
    return controller;
}

void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
    registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());
}

至此,SavedStateProviderSavedStateRegistry實(shí)現(xiàn)關(guān)聯(lián)裁良。


以上就是整個保存流程的概況凿将,而還原流程差距不大,只是在onCreate()中調(diào)用SavedStateRegistryController.performRestore()价脾,最終通知SavedStateRegistryBundle中恢復(fù)設(shè)置的數(shù)據(jù)丸相。


忽略SavedStateHandleControllerVM的確保機(jī)制 (包含Recreator),最后總結(jié):

  • 簡化稱呼以縮短閱讀量:
    --
    VM組:
    ViewModel = VM
    SavedStateViewModelFactory = Factory
    --
    Registry組:
    SavedStateRegistryController = RegistryController
    SavedStateRegistry = Registry
    --
    Handle組:
    SavedStateHandleController = HandleController
    SavedStateHandle = Handle
    --
    Provider組:
    SavedStateProvider = Provider
    --
  • 初始化階段:
    ComponentActivity創(chuàng)建了RegistryController實(shí)例
    RegistryController創(chuàng)建了內(nèi)部的Registry實(shí)例
    ComponentActivity創(chuàng)建了Factory彼棍,并傳入RegistryController維護(hù)的Registry

  • 恢復(fù)階段
    ComponentActivityonCreate調(diào)用RegistryControllerperformRestore
    RegistryControllerperformRestore中灭忠,調(diào)用RegistryperformRestore
    RegistryperformRestore中,把數(shù)據(jù)從savedInstanceState (Bundle)取出座硕,并儲存到mRestoredState
    在此處Registry已把數(shù)據(jù)恢復(fù)

  • VM生成階段:
    VM需要通過Factory創(chuàng)建弛作,創(chuàng)建過程:
    -- 創(chuàng)建VM對應(yīng)的HandleController實(shí)例,創(chuàng)建過程:
    ------ 通過RegistryconsumeRestoredStateForKey把數(shù)據(jù)取出生成Handle
    ------ Handle內(nèi)部維護(hù)一個Provider實(shí)例华匾,共享數(shù)據(jù)容器mRegular
    ------ HandleController被注入Handle
    ------ Provider綁定到Registry
    ------ 在此處實(shí)現(xiàn)了 (RegistryController-Registry-Provider-Handle) 綁定
    --VMFactory注入Handle
    --在此處實(shí)現(xiàn)了 (RegistryController-Registry-Provider-Handle-VM) 綁定
    --VM數(shù)據(jù)最終通過Registry恢復(fù)

  • 寫數(shù)據(jù)階段
    VM讀寫的數(shù)據(jù)最終存放到HandlemRegular
    VM數(shù)據(jù)最終通過Registry保存

  • 保存階段
    ComponentActivityonSaveInstanceState調(diào)用RegistryControllerperformSave
    RegistryControllerperformSave中映琳,調(diào)用RegistryperformSave
    RegistryperformSave中机隙,將所有注冊的Provider數(shù)據(jù)打包成一個Bundle保存到onSaveInstanceStateBundle
    在此處Registry已把數(shù)據(jù)保存

·

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市萨西,隨后出現(xiàn)的幾起案子有鹿,更是在濱河造成了極大的恐慌,老刑警劉巖谎脯,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葱跋,死亡現(xiàn)場離奇詭異,居然都是意外死亡源梭,警方通過查閱死者的電腦和手機(jī)娱俺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來废麻,“玉大人荠卷,你說我怎么就攤上這事≈蚶ⅲ” “怎么了油宜?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長怜姿。 經(jīng)常有香客問我验庙,道長,這世上最難降的妖魔是什么社牲? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮悴了,結(jié)果婚禮上搏恤,老公的妹妹穿的比我還像新娘。我一直安慰自己湃交,他們只是感情好熟空,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搞莺,像睡著了一般息罗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上才沧,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天迈喉,我揣著相機(jī)與錄音,去河邊找鬼温圆。 笑死挨摸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岁歉。 我是一名探鬼主播得运,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了熔掺?” 一聲冷哼從身側(cè)響起饱搏,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎置逻,沒想到半個月后推沸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诽偷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年坤学,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片报慕。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡深浮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出眠冈,到底是詐尸還是另有隱情飞苇,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布蜗顽,位于F島的核電站布卡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏雇盖。R本人自食惡果不足惜忿等,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望崔挖。 院中可真熱鬧贸街,春花似錦、人聲如沸狸相。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脓鹃。三九已至逸尖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瘸右,已是汗流浹背娇跟。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留太颤,地道東北人逞频。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像栋齿,于是被迫代替她去往敵國和親苗胀。 傳聞我的和親對象是個殘疾皇子襟诸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355