Android Architecture Component之ViewModel解析

博文出處:Android Architecture Component之ViewModel解析,歡迎大家關(guān)注我的博客,謝謝!

Header

之前給大家分析過了 LiveData ,今天就來看看 ViewModel 。

ViewModel 的作用就相當(dāng)于 MVP 中的 Presenter ,是用來銜接 Model 和 View 的。通常把一些與 View 無關(guān)的業(yè)務(wù)邏輯寫在 ViewModel 里面。ViewModel 內(nèi)部創(chuàng)建出 LiveData 對(duì)象,利用 LiveData 對(duì)象來傳遞數(shù)據(jù)給 View 。

ViewModel 相對(duì)于 Presenter 而言,有以下幾個(gè)好處:

  1. ViewModel 并不直接持有 View ,所以在 ViewModel 銷毀時(shí)不需要像 Presenter 一樣地去手動(dòng)解除 View 的綁定,也就不會(huì)造成持有 View 導(dǎo)致的內(nèi)存泄漏;
  2. 比如 Activity 配置改變的情況下,ViewModel 會(huì)保存不會(huì)丟失數(shù)據(jù);
  3. ViewModel 可以做到在同一個(gè) Activity 的情況下,多個(gè) Fragment 共享數(shù)據(jù);

下面是官方給出的 ViewModel 生命周期圖,大家隨意感受一下:

[圖片上傳失敗...(image-e38635-1531153914120)]

那么就開始進(jìn)入正題吧。

本次解析的 ViewModel 源碼基于 android.arch.lifecycle:extensions:1.1.1

ViewModel

先來看看 ViewModel 是怎么被創(chuàng)建出來的:

    XXXViewModel xxxViewModel = ViewModelProviders.of(activity).get(XXXViewModel.class)

可以看到 ViewModel 并不是簡(jiǎn)單地 new 出來的,這其中的邏輯要需要我們一步一步慢慢揭開。

那么 ViewModel 是怎樣被定義的呢?

ViewModel

public abstract class ViewModel {
    /**
     * This method will be called when this ViewModel is no longer used and will be destroyed.
     * <p>
     * It is useful when ViewModel observes some data and you need to clear this subscription to
     * prevent a leak of this ViewModel.
     */
    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
    }
}

原來 ViewModel 是個(gè)抽象類,里面只有一個(gè) onCleared() 方法。 onCleared() 會(huì)在 ViewModel 被銷毀時(shí)回調(diào),所以可以在 onCleared() 里面做一些釋放資源、清理內(nèi)存的操作。

另外,ViewModel 還有一個(gè)子類: AndroidViewModel 。AndroidViewModel 在 ViewModel 的基礎(chǔ)上內(nèi)部包含了 application 。

ViewModelProviders

我們就來抽絲剝繭了,先從 ViewModelProviders 入手。創(chuàng)建 ViewModel 時(shí)在 ViewModelProviders 中調(diào)用了 of 方法。

of

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

    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment) {
        return of(fragment, 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 方法可以分為兩個(gè)入口,分別對(duì)應(yīng)著 Fragment 和 Activity 。這也說明了 ViewModel 的作用域其實(shí)是分為兩個(gè)維度的。但是這兩個(gè)方法內(nèi)部的代碼很像,邏輯基本都是:

  1. 先去獲取 application ;
  2. 創(chuàng)建 factory ;
  3. 創(chuàng)建 ViewModelProvider ,ViewModelProvider 顧名思義就是提供 ViewModel 的;

第一步就不用說了,直接進(jìn)入第二步吧。

Factory

Factory 是什么東東呢,說白了就是 ViewModel 的制造工廠。所有的 ViewModel 都是由 Factory 來創(chuàng)建出來的。

    public interface Factory {
        /**
         * Creates a new instance of the given {@code Class}.
         * <p>
         *
         * @param modelClass a {@code Class} whose instance is requested
         * @param <T>        The type parameter for the ViewModel.
         * @return a newly created ViewModel
         */
        @NonNull
        <T extends ViewModel> T create(@NonNull Class<T> modelClass);
    }

Factory 是個(gè)接口,里面定義了 create 方法來創(chuàng)建 ViewModel 。來看看它的實(shí)現(xiàn)類 NewInstanceFactory 。

NewInstanceFactory

    /**
     * Simple factory, which calls empty constructor on the give class.
     */
    public static class NewInstanceFactory implements Factory {

        @SuppressWarnings("ClassNewInstance")
        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            //noinspection TryWithIdenticalCatches
            try {
                return modelClass.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            }
        }
    }

其實(shí)沒啥好說的,就是利用反射來創(chuàng)建實(shí)例了,是一個(gè)很簡(jiǎn)單的實(shí)現(xiàn)類。NewInstanceFactory 其實(shí)是創(chuàng)建普通 ViewModel 的工廠,而如果想創(chuàng)建 AndroidViewModel 的話,工廠就要選擇 AndroidViewModelFactory 了。

AndroidViewModelFactory

    /**
     * {@link Factory} which may create {@link AndroidViewModel} and
     * {@link ViewModel}, which have an empty constructor.
     */
    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

        private static AndroidViewModelFactory sInstance;

        /**
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * @param application an application to pass in {@link AndroidViewModel}
         * @return A valid {@link AndroidViewModelFactory}
         */
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

        private Application mApplication;

        /**
         * Creates a {@code AndroidViewModelFactory}
         *
         * @param application an application to pass in {@link AndroidViewModel}
         */
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }

        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                //noinspection TryWithIdenticalCatches
                try {
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InstantiationException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                }
            }
            return super.create(modelClass);
        }
    }

發(fā)現(xiàn)在 AndroidViewModelFactory 的 create 方法中,對(duì)創(chuàng)建 ViewModel 的方案做了兼容,所以 AndroidViewModelFactory 是同時(shí)適用于創(chuàng)建 ViewModel 和 AndroidViewModel 的。并且 AndroidViewModelFactory 是單例工廠,防止多次創(chuàng)建浪費(fèi)內(nèi)存。

額外補(bǔ)充一點(diǎn),在 ViewModelProviders 中有一個(gè)內(nèi)部類 DefaultFactory ,現(xiàn)在已經(jīng)被打上廢棄的標(biāo)簽了,可以猜出這個(gè) DefaultFactory 應(yīng)該是早期版本的默認(rèn)工廠類,現(xiàn)在已經(jīng)被 AndroidViewModelFactory 代替了。

ViewModelStores

到這里 Factory 就有了,那么就重點(diǎn)來看看 ViewModelStores.of(activity) 這段代碼了。ViewModelStores 是根據(jù)作用域用來提供 ViewModelStore 的,而 ViewModelStore 的作用就是存儲(chǔ) ViewModel ,內(nèi)部是利用 key/value 將 ViewModel 保存在 HashMap 中,方便讀寫,這里就不展示 ViewModelStore 的源碼了,大家可以把 ViewModelStore 當(dāng)作 HashMap 就行。

    /**
     * Factory methods for {@link ViewModelStore} class.
     */
    @SuppressWarnings("WeakerAccess")
    public class ViewModelStores {
    
        private ViewModelStores() {
        }
    
        /**
         * Returns the {@link ViewModelStore} of the given activity.
         *
         * @param activity an activity whose {@code ViewModelStore} is requested
         * @return a {@code ViewModelStore}
         */
        @NonNull
        @MainThread
        public static ViewModelStore of(@NonNull FragmentActivity activity) {
            if (activity instanceof ViewModelStoreOwner) {
                return ((ViewModelStoreOwner) activity).getViewModelStore();
            }
            return holderFragmentFor(activity).getViewModelStore();
        }
    
        /**
         * Returns the {@link ViewModelStore} of the given fragment.
         *
         * @param fragment a fragment whose {@code ViewModelStore} is requested
         * @return a {@code ViewModelStore}
         */
        @NonNull
        @MainThread
        public static ViewModelStore of(@NonNull Fragment fragment) {
            if (fragment instanceof ViewModelStoreOwner) {
                return ((ViewModelStoreOwner) fragment).getViewModelStore();
            }
            return holderFragmentFor(fragment).getViewModelStore();
        }
    }

根據(jù) ViewModelProviders 的思路,ViewModelStores 也是分為了兩個(gè)方法,對(duì)應(yīng)著 Fragment 和 Activity 。

  1. 如果 Activity 和 Fragment 實(shí)現(xiàn)了 ViewModelStoreOwner 的接口,那么直接返回內(nèi)部的 ViewModelStore 就行了;
  2. 如果是之前老早版本的 Activity 或者 Fragment ,那么它們肯定是沒有實(shí)現(xiàn) ViewModelStoreOwner 接口的,那該怎么辦呢?很簡(jiǎn)單,新創(chuàng)建一個(gè) Fragment 來關(guān)聯(lián) ViewModelStoreOwner 就好了??!

所以就有了 holderFragmentFor(activity) 和 holderFragmentFor(fragment) 這段了。

HolderFragment

HolderFragment 實(shí)現(xiàn)了 ViewModelStoreOwner 接口,所以 HolderFragment 的作用就是代替了那些之前沒有實(shí)現(xiàn) ViewModelStoreOwner 接口的 Activity/Fragment 。這樣,Activity/Fragment 也間接地?fù)碛辛?ViewModelStore 。

HolderFragment 的代碼我們就只看 holderFragmentFor(activity) 這一段吧,holderFragmentFor(fragment) 也是類似的。

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

    static class HolderFragmentManager {

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

其實(shí)就是把 HolderFragment 添加進(jìn) Activity 里面,這樣 HolderFragment 就和 Activity 的生命周期關(guān)聯(lián)在一起了。實(shí)際上獲取的就是 HolderFragment 里面的 ViewModelStore 。每個(gè) Activity 里面只有一個(gè) HolderFragment 。

Fragment 也是同理,利用 getChildFragmentManager() 來往里添加 HolderFragment 。這里就不講了,有興趣的同學(xué)可以自己回去看看源碼。

至此,用來創(chuàng)建 ViewModelProvider 的兩個(gè)入?yún)?ViewModelStore 和 Factory 都講完了。

ViewModelProvider

創(chuàng)建出 ViewModelProvider 后,最后一步就是調(diào)用它的 get 方法返回 ViewModel 了。

    @NonNull
    @MainThread
    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);
    }

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

get 方法很 easy ,就是利用 class 的 canonicalName 生成一個(gè)唯一的 key ,然后利用 key 去 mViewModelStore 中獲取。如果有值就返回,否則就利用 factory 創(chuàng)建新的 ViewModel ,然后保存到 mViewModelStore 中并返回。

整個(gè) ViewModel 的源碼流程基本上就講完了,其實(shí)并不復(fù)雜?;厝ザ喽囿w會(huì),總能明白其中的奧秘。

下面,額外給大家補(bǔ)充幾個(gè)小點(diǎn),加個(gè)雞腿。

Tip

ViewModel的onCleared什么時(shí)候回調(diào)

之前說過,ViewModel 是保存在 ViewModelStore 里面的,所以 ViewModel 的銷毀一定是在 ViewModelStore 里面操作的。

ViewModelStore

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }

可以看到 ViewModelStore 的 clear() 方法內(nèi)部調(diào)用 ViewModel 的 onCleared() 方法。那么哪里調(diào)用了 ViewModelStore 的 clear() 方法呢?

Fragment

    /**
     * Called when the fragment is no longer in use.  This is called
     * after {@link #onStop()} and before {@link #onDetach()}.
     */
    @CallSuper
    public void onDestroy() {
        mCalled = true;
        // Use mStateSaved instead of isStateSaved() since we're past onStop()
        if (mViewModelStore != null && !mHost.mFragmentManager.mStateSaved) {
            mViewModelStore.clear();
        }
    }

可以從代碼上看到,F(xiàn)ragment 的銷毀操作調(diào)用是在 onDestroy() 中。

另外,如果狀態(tài)保存標(biāo)記值 mStateSaved 為 true 的情況下,是不會(huì)去清除 ViewModel 的,這也是為什么上面中講的配置改變的情況下,數(shù)據(jù)得以保持住的原因。

FragmentActivity

    /**
     * Destroy all fragments.
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();

        doReallyStop(false);

        if (mViewModelStore != null && !mRetaining) {
            mViewModelStore.clear();
        }

        mFragments.dispatchDestroy();
    }

同理, Activity 的銷毀操作也是在 onDestroy() 完成的。

Footer

終于把 LiveData 和 ViewModel 都分析了一遍,現(xiàn)在還差一個(gè) Lifecycle 。

那么等有時(shí)間再寫吧,bye bye!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容