Android Jetpack——ViewModel源碼解析

一副女、前言

之前我們已經(jīng)介紹了ViewModel的意義和使用方式蛤高。我們知道,在一個Activity創(chuàng)建ViewModel對象的時候,當由于系統(tǒng)配置變化導致Activity銷毀重建的時候襟齿,ViewModel對象并不會被有任何影響姻锁,由此可知在ViewModel中存儲的數(shù)據(jù),也不會發(fā)生變化猜欺。這對于我們開發(fā)者來說是很方便的位隶。
我們知道Activity的onSaveInstanceState和onRestoreInstanceState也可以做到這一點,但是我們知道onSaveInstanceState和onRestoreInstanceState是通過把數(shù)據(jù)序列化到內(nèi)存开皿,再從內(nèi)存中反序列化出來涧黄。通常是針對一些可以序列化和反序列化的小量數(shù)據(jù),如果是大量的數(shù)據(jù)赋荆,或者沒有序列化的笋妥,則不行了。
了解了ViewModel的強大的功能之后窄潭,我們先用一張圖來描述ViewModel的生命周期的變化:


image.png

從圖中我們可以看到春宣,只有Activity真正的銷毀的時候,ViewModel才會被清除掉嫉你,對應圖中的onCleared方法月帝。

二、源碼解析

下面我們來分析ViewModel的源碼幽污。我們先看下ViewModel對象的創(chuàng)建方式:

   viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

代碼很簡單嚷辅,首先調(diào)用ViewModelProviders的of方法創(chuàng)建ViewModelProvider對象。其實從類的命名上看就很容易理解距误,ViewModelProviders和ViewModelProvider只差一個s簸搞,ViewModelProviders是一個集合,ViewModelProvider是集合中的一個對象准潭,of(this)則是通過傳入當前Activitiy的實例作為key趁俊,獲取ViewModelProviders中ViewModelProvider對象。是不是這個意思呢刑然?我們繼續(xù)分析:

 @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment) {
        return of(fragment, null);
    }

  @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        return of(activity, null);
    }

   @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
        Application application = checkApplication(checkActivity(fragment));
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(ViewModelStores.of(fragment), factory);
    }

  @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
        Application application = checkApplication(activity);
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }

我們看到of方法中有四個重載的方法寺擂,她們的區(qū)別就是傳入的this是Activity還是Fragment,還有就是闰集,是否有Factory 對象沽讹。如果沒有Factory對象,則創(chuàng)建默認的Factory武鲁。然后通過以下方式返回ViewModelProvider 對象

 return new ViewModelProvider(ViewModelStores.of(fragment), factory);

我們看下ViewModelProvider的構(gòu)造函數(shù):

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

ViewModelStore 和Factory 對象顧名思義ViewModelStore 是用來存儲ViewModel的Factory 是用來創(chuàng)建ViewModel的爽雄。通過ViewModelStores.of(fragment)創(chuàng)建獲取ViewModelStore實例,接著我們看下ViewModelStores.of(fragment)的實現(xiàn)

  @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull Fragment fragment) {
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        return holderFragmentFor(fragment).getViewModelStore();
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(Fragment fragment) {
        return sHolderFragmentManager.holderFragmentFor(fragment);
    }

 HolderFragment holderFragmentFor(Fragment parentFragment) {
            FragmentManager fm = parentFragment.getChildFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedFragmentHolders.get(parentFragment);
            if (holder != null) {
                return holder;
            }

            parentFragment.getFragmentManager()
                    .registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
            holder = createHolderFragment(fm);
            mNotCommittedFragmentHolders.put(parentFragment, holder);
            return holder;
        }

    HolderFragment holderFragmentFor(FragmentActivity activity) {
            FragmentManager fm = activity.getSupportFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedActivityHolders.get(activity);
            if (holder != null) {
                return holder;
            }

            if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
                activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
            }
            holder = createHolderFragment(fm);
            mNotCommittedActivityHolders.put(activity, holder);
            return holder;
        }

我們看到獲取ViewModelStore實例最終調(diào)用了holderFragmentFor方法獲取HolderFragment 實例holder 沐鼠,而HolderFragment 繼承了ViewModelStoreOwner挚瘟。在holderFragmentFor方法中首先根據(jù)activity作為key叹谁,判斷holder 是否存在。如果存在里乘盖,就直接返回holder焰檩。

  HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedActivityHolders.get(activity);
            if (holder != null) {
                return holder;
            }

如果不存在則創(chuàng)建新的holder返回,并把holde存到mNotCommittedActivityHolders這個Map中订框,以Activity作為key析苫。

 if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
                activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
            }
            holder = createHolderFragment(fm);
            mNotCommittedActivityHolders.put(activity, holder);
            return holder;

這樣一來我們可以知道,只要HolderFragment 沒有被銷毀穿扳,mNotCommittedActivityHolders這個Map就會存在衩侥,那么存放在Map中的ViewModelStoreOwner holder就存在。

return holderFragmentFor(fragment).getViewModelStore();

然后通過getViewModelStore()方法可以得到ViewModelStore對象矛物。
接著我們看下get方法

  viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

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

        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }

        viewModel = mFactory.create(modelClass);
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }

我們很容易知道茫死,首先從Map中根據(jù)key獲取ViewModel 對象

ViewModel viewModel = mViewModelStore.get(key);

如果viewModel 不為空,則返回履羞,否則創(chuàng)建一個ViewModel對象峦萎,存放在Map中。

  ViewModel oldViewModel = mMap.put(key, viewModel);

并且我們知道存放ViewModel的Key和Activity或者Fragment是對應起來的忆首。所以說當Activity重建的時候爱榔,只要mViewModelStore對象還是原來的對象,那么ViewModel對象就不會變雄卷,而且我們在上面分析知道m(xù)ViewModelStore又存放到了HolderFragment中搓蚪,也是存放到了Map中蛤售,所以只要HolderFragment沒有被銷毀丁鹉,mViewModelStore就不會被銷毀。mViewModelStore沒有被銷毀悴能,ViewModel就沒有被銷毀揣钦。ViewModel沒有被銷毀,ViewModel里面的數(shù)據(jù)就沒有被銷毀漠酿。因此得出了我們的結(jié)論冯凹。在Activity銷毀重建的時候,ViewModel里的數(shù)據(jù)是不會丟失的炒嘲。

三宇姚、小結(jié)

我們對ViewModel的源碼做一個小結(jié):
1、創(chuàng)建HolderFragment夫凸,并在HolderFragment中初始化Map<Activity, HolderFragment> mNotCommittedActivityHolders 用于存放 HolderFragment holder浑劳。
2、從HolderFragment 獲取ViewModelStore mViewModelStore
3夭拌、ViewModelStore 用于存放ViewModel對象魔熏,創(chuàng)建ViewModelProvider實例衷咽,傳入ViewModelStore 對象,對ViewModelProvider中的ViewModelStore進行初始化蒜绽。
4镶骗、通過 mViewModelStore.put(key, viewModel);獲取ViewModel實例。
其實ViewModel最核心的部分就是HolderFragment 中存放了ViewModelStore 躲雅。因為Activity在銷毀重建的時候HolderFragment 并不收到影響鼎姊,所以ViewModelStore 不會丟失。從而下面的一系列得到ViewModel對象不會銷毀相赁。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末此蜈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子噪生,更是在濱河造成了極大的恐慌裆赵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跺嗽,死亡現(xiàn)場離奇詭異战授,居然都是意外死亡,警方通過查閱死者的電腦和手機桨嫁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門植兰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人璃吧,你說我怎么就攤上這事楣导。” “怎么了畜挨?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵筒繁,是天一觀的道長。 經(jīng)常有香客問我巴元,道長毡咏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任逮刨,我火速辦了婚禮呕缭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘修己。我一直安慰自己恢总,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布睬愤。 她就那樣靜靜地躺著片仿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戴涝。 梳的紋絲不亂的頭發(fā)上滋戳,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天钻蔑,我揣著相機與錄音,去河邊找鬼奸鸯。 笑死咪笑,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的娄涩。 我是一名探鬼主播窗怒,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蓄拣!你這毒婦竟也來了扬虚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤球恤,失蹤者是張志新(化名)和其女友劉穎辜昵,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咽斧,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡堪置,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了张惹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舀锨。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宛逗,靈堂內(nèi)的尸體忽然破棺而出坎匿,到底是詐尸還是另有隱情,我是刑警寧澤雷激,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布替蔬,位于F島的核電站,受9級特大地震影響侥锦,放射性物質(zhì)發(fā)生泄漏进栽。R本人自食惡果不足惜德挣,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一恭垦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧格嗅,春花似錦番挺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贴铜,卻和暖如春粪摘,著一層夾襖步出監(jiān)牢的瞬間瀑晒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工徘意, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留苔悦,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓椎咧,卻偏偏與公主長得像玖详,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子勤讽,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容