AndroidX設計架構MVVM之ViewModel生命週期分析

本文基於ViewModel 2.1.0
先來一張ViewModel生命週期圖

原文
AndroidX設計架構MVVM之ViewModel創建流程原理分析
AndroidX設計架構MVVM之ViewModel生命週期分析
AndroidX設計架構MVVM之LiveDatal生命週期及數據監聽分析
AndroidX設計架構MVVM之DataBinding搭配LiveData的分析
AndroidX設計架構MVVM之DataBinding+ViewModel+LiveData
在這裏插入圖片描述
從google官網獲取的ViewModel生命週期圖,圖中顯示activity在橫豎屏旋轉重建時ViewModel一直存在內存中
ViewModel創建流程原理分析的總結中提到一個activity中只有一個ViewModelStore,ViewModelStore中保存此activity中所有ViewModel。

那麼根據ViewModel的生命週期圖來看看,當activity在生命週期onDestroy中是如何處理ViewModel的。

@Override
    protected void onDestroy() {
        super.onDestroy();
        //注意點1
        if (mViewModelStore != null && !isChangingConfigurations()) {
        //注意點2
            mViewModelStore.clear();
        }
        mFragments.dispatchDestroy();
    }

注意點1:關鍵點isChangingConfigurations(),從名字上就知道是判斷當前是否爲切換橫豎屏。

 public boolean isChangingConfigurations() {
        return mChangingConfigurations;
    }
    
 /** true if the activity is being destroyed in order to recreate it with a new configuration */
    /*package*/ boolean mChangingConfigurations = false;

mChangingConfigurations 屬性的註釋:當爲true時,表示activity使用新的configuration 進行重建。這部分放到最下面分析,現在只需要知道mChangingConfigurations =ture,activity重建時,不執行(注意點2) mViewModelStore.clear();

那麼問題來了,old activity都銷燬了,它包含的ViewModelStore怎麼會沒有回收呢?
在activity旋轉重建,銷燬old activity前,對當前的ViewModelStore進行了保存,然後在新生成的activity中進行了恢復。

先看保存的地方,old activity執行onDestroy時會執行onRetainNonConfigurationInstance,保存當前的mViewModelStore。

 public final Object onRetainNonConfigurationInstance() {
       。。。。。。
       //保存mViewModelStore
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = mViewModelStore;
        nci.fragments = fragments;
        return nci;
    }

再看恢復的地方,主要有兩個地方activity的onCreate中和getViewModelStore()()可以參考ViewModel創建流程原理分析

//恢復地方1
 protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);

        super.onCreate(savedInstanceState);

        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
         //判斷最後保存的非配置實例不爲空,且保存的viewModelStore 不爲空
         //而當前activity的mViewModelStore 爲空時進行賦值
        if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {
            mViewModelStore = nc.viewModelStore;
        }
        。。。。。。。
   }
   
  //恢復地方2 
 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) {
                //由於在oncreate中恢復過,所以爲重新恢復
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

###############################################################################
下面分析mChangingConfigurations 在什麼地方設置爲true。不關心的話這部分可以不看哈

但activity重建時會調用recreate(),註釋說明會銷燬現有的activity實例,重建一個先的實例

 /**
     * Cause this Activity to be recreated with a new instance.  This results
     * in essentially the same flow as when the Activity is created due to
     * a configuration change -- the current instance will go through its
     * lifecycle to {@link #onDestroy} and a new instance then created after it.
     */
    public void recreate() {
        if (mParent != null) {
            throw new IllegalStateException("Can only be called on top-level activity");
        }
        if (Looper.myLooper() != mMainThread.getLooper()) {
            throw new IllegalStateException("Must be called from main thread");
        }
        //注意點3
        mMainThread.scheduleRelaunchActivity(mToken);
    }

注意點3:通過ActivityThread發送RELAUNCH_ACTIVITY 的message。

 void scheduleRelaunchActivity(IBinder token) {
        sendMessage(H.RELAUNCH_ACTIVITY, token);
    }
//handler中接收到消息
 case RELAUNCH_ACTIVITY:
                    //注意點4  
                    handleRelaunchActivityLocally((IBinder) msg.obj);
                    break;
    }

注意點4:這部分簡單說吧(對本文沒特別大的意義)。handleRelaunchActivityLocally()的一部分工作就是合併新的和舊的配置到新創建的activity中,最終會走到activityThread的handleRelaunchActivity().並修改mChangingConfigurations 爲true

public void handleRelaunchActivity(ActivityClientRecord tmp,
            PendingTransactionActions pendingActions) {
            ....................
            //在執行重新創建的中修改爲true
             r.activity.mChangingConfigurations = true;
            ....................

總結:如果activity的生命週期是因爲發生旋轉造成的,那麼在old activity銷燬的時候,保存了ViewModelStore對象,並將old activity 的mChangingConfigurations 設置爲true,即不清空ViewModelStore中保存的ViewModel。當新new activity執行oncreate時,賦值給new activity的mViewModelStore,並在獲取new activity的ViewModelStore時重新賦值(爲啥要重新賦值????暫時沒有分析)。

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