Android Jetpack Architecture原理之ViewModel


??Jetpack已經(jīng)出了很久很久了,近幾年的GDD幾乎每次都會(huì)介紹新的組件,說(shuō)來(lái)慚愧,一直沒有好好學(xué)習(xí),看近年的Google 的很多Demo中其實(shí)都有所體現(xiàn),之前都是大概的了解了一遍。最近決定,好好梳理一遍,既學(xué)習(xí)其用法,也嘗試學(xué)習(xí)下其設(shè)計(jì)思想。也是時(shí)候該補(bǔ)充一下了。進(jìn)入正題--ViewModel

??首先都是看官方的例子,ViewModel官方的的例子是會(huì)和另一個(gè)架構(gòu)庫(kù)LiveData寫在一起,很多的博客也是照官方的例子來(lái)說(shuō)明,開始接觸時(shí)甚至給了我一種假象:ViewModel都是和LiveData一起使用的。后來(lái)閱讀才了解,ViewModel和LiveData職責(zé)分工還是很明顯的,使用LiveData Demo主要使用其observe功能,LiveDate的使用及原理之后再分析,甚至在appcompat-v7:27.1.1中直接單獨(dú)集成了ViewModel.所以,故為排除干擾,今天不會(huì)使用官方的主流Demo用法,先來(lái)看ViewModel。

??Android的UI控制器(Activity和Fragment)從創(chuàng)建到銷毀擁有自己完整的生命周期,當(dāng)系統(tǒng)配置發(fā)生改變時(shí)((Configuration changes)),系統(tǒng)就會(huì)銷毀Activity和與之關(guān)聯(lián)的Fragment然后再次重建<font color=#FFA500>(可通過(guò)在AndroidManifast.xml中配置android:configChanges修改某些行為,這里不討論)</font>,那么存儲(chǔ)在當(dāng)前UI中的臨時(shí)數(shù)據(jù)也會(huì)被清空,例如,登陸輸入框,輸入賬號(hào)或密碼后旋轉(zhuǎn)屏幕,視圖被重建,輸入過(guò)的數(shù)據(jù)也清空了,這無(wú)疑是一種不友好的用戶體驗(yàn)。對(duì)于少量的可序列化數(shù)據(jù)可以使用onSaveInstanceState()方法保存然后在onCreate()方法中重新恢復(fù),正如所說(shuō)onSaveInstanceState對(duì)于大量的數(shù)據(jù)緩存有一定的局限性,大量的數(shù)據(jù)緩存則可以使用Fragment.setRetainInstance(true)來(lái)保存數(shù)據(jù)。ViewModel也是提供了相同的功能,其實(shí)和“RetainInstance”也有關(guān)聯(lián),用來(lái)存儲(chǔ)和管理與UI相關(guān)的數(shù)據(jù),允許數(shù)據(jù)在系統(tǒng)配置變化后存活,我們一起看一下這個(gè)ViewModel的緩存是怎么實(shí)現(xiàn)的呢?

使用方式
首先先看下使用方式,先上效果圖

ViewMode Sample

public class MyViewModel extends ViewModel {
    String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
    @Override
    protected void onCleared() {
        super.onCleared();
        name = null;
    }
}

?

public class ViewModelActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "ViewModelActivity";
    TextView textView;
    private MyViewModel myViewModel;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_viewmodel);
        textView = findViewById(R.id.textView);
        textView.setOnClickListener(this);
        ViewModelProvider.Factory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());
    /*
    *這里的this是ViewModelStoreOwner接口在appcompat-v7:27.1.1支持庫(kù)中AppCompatActivity已經(jīng)實(shí)現(xiàn)了,       
    *如果是較低版本,需要更新支持包或者參考其實(shí)現(xiàn)對(duì)本來(lái)繼承的Activity做對(duì)應(yīng)實(shí)現(xiàn)。
    */
        ViewModelProvider provider = new ViewModelProvider(this, factory);//
        myViewModel = provider.get(MyViewModel.class);
        Log.e(TAG, "onCreate: " + myViewModel.getName() );
        if (myViewModel.getName() != null) {
            textView.setText(myViewModel.getName());
        }
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.textView:
                myViewModel.setName("MyViewModel Test");
                textView.setText(myViewModel.getName());
                break;
        }
    }
}

?

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:text="default"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

非常簡(jiǎn)單的一個(gè)例子,這就是ViewModel最簡(jiǎn)單的使用了,就是TextView中顯示ViewModel的數(shù)據(jù)。ViewModel需要由ViewModelProvider.get(Class<T>)來(lái)取得,旋轉(zhuǎn)屏幕銷毀后,之前改變的數(shù)據(jù)還在。
發(fā)現(xiàn)的一些疑問(wèn)
接下來(lái)就是進(jìn)入主題分析下ViewModel到底是怎么實(shí)現(xiàn)的呢?
帶著問(wèn)題看源碼:

  • ViewModelProvider是干啥的?
  • AndroidViewModelFactory 這命名一看就是應(yīng)該是工廠模式,工廠創(chuàng)建了什么?
  • provider.get(MyViewModel.class) 這里直接使用的get命名就得到了需要的唯一數(shù)據(jù)
  • 注釋中ViewModelStoreOwner又是什么角色?
    源碼分析
    先看ViewModel類,沒什么說(shuō)的,就是一個(gè)么有任何真正實(shí)現(xiàn)的抽象類,只有一個(gè)抽象方法onCleared()
  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() {
      }
  }

接著看下ViewModelFactory,顧名思義就是制造ViewModel的。
AndroidViewModelFactory的繼承關(guān)系如下:

android.arch.lifecycle.ViewModelProvider.Factory

android.arch.lifecycle.ViewModelProvider.NewInstanceFactory

android.arch.lifecycle.ViewModelProvider.AndroidViewModelFactory

Factory是一個(gè)只包含一個(gè)create的interface,NewInstanceFactory實(shí)現(xiàn)了該方法傳入Class<T>會(huì)利用ViewModel的默認(rèn)無(wú)參構(gòu)造器創(chuàng)建一個(gè)對(duì)應(yīng)ViewModel的實(shí)例,而AndroidViewModelFactory增加了一個(gè)屬性就是應(yīng)用的Applicaion,同時(shí)重寫create方法,查看ViewModel是否有包含Applicaion參數(shù)的構(gòu)造方法從而使用,對(duì)應(yīng)的其實(shí)還有一個(gè)AndroidViewModel是ViewModel的子類,默認(rèn)已經(jīng)實(shí)現(xiàn)了帶有Application參數(shù)的構(gòu)造方法,需要使用在ViewModel中使用application的直接繼承AndroidViewModel就可以,看到這里其實(shí)最上面的例子有個(gè)不是問(wèn)題的問(wèn)題,其實(shí)上面的Factory直接使用NewInstanceFactory就可以創(chuàng)建出對(duì)應(yīng)的ViewModel實(shí)例了。

    /**
     * Implementations of {@code Factory} interface are responsible to instantiate ViewModels.
     */
    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);
    }

/**
 * 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);
        }
    }
}
/**
 * {@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);
    }
}

之后通過(guò)ViewModelStoreOwner和剛剛創(chuàng)建的Factory創(chuàng)建出ViewModelPrivider實(shí)例

/**
 * Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given
 * {@code Factory} and retain them in a store of the given {@code ViewModelStoreOwner}.
 *
 * @param owner   a {@code ViewModelStoreOwner} whose {@link ViewModelStore} will be used to
 *                retain {@code ViewModels}
 * @param factory a {@code Factory} which will be used to instantiate
 *                new {@code ViewModels}
 */
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
    this(owner.getViewModelStore(), factory);
}

/**
 * Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given
 * {@code Factory} and retain them in the given {@code store}.
 *
 * @param store   {@code ViewModelStore} where ViewModels will be stored.
 * @param factory factory a {@code Factory} which will be used to instantiate
 *                new {@code ViewModels}
 */
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
    mFactory = factory;
    this.mViewModelStore = store;
}
/**
 * A scope that owns {@link ViewModelStore}.
 * <p>
 * A responsibility of an implementation of this interface is to retain owned ViewModelStore
 * during the configuration changes and call {@link ViewModelStore#clear()}, when this scope is
 * going to be destroyed.
 */
@SuppressWarnings("WeakerAccess")
public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}

ViewModelStoreOwner 也是一個(gè)接口是FragmentActivity實(shí)現(xiàn)了該接口并實(shí)現(xiàn)了其中的getViewModelStore()方法

public class FragmentActivity extends BaseFragmentActivityApi16 implements
        ViewModelStoreOwner...{
    private ViewModelStore mViewModelStore;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);

        super.onCreate(savedInstanceState);

        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            mViewModelStore = nc.viewModelStore;
    }
    /**
     * Returns the {@link ViewModelStore} associated with this activity
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    @Override
    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) {
            mViewModelStore = new ViewModelStore();
        }
        return mViewModelStore;
    }
}

這個(gè)ViewModelStore又是什么呢,其實(shí)就是真正利用HashMap存儲(chǔ)ViewModel的地方了,看下代碼在存儲(chǔ)和clear同時(shí)會(huì)調(diào)用ViewModel需要實(shí)現(xiàn)的抽象方法onClear()

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

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

這樣ViewModelProvider就是有了一個(gè)ViewModel的容器,這時(shí)去調(diào)用ViewModelProvider的get(Class<T>)方法就是去調(diào)用mViewModelStore
的get()方法取出對(duì)應(yīng)的ViewModel所以這里只要持有的ViewModelStore是有緩存的,那么取出的ViewModel就是相同的緩存了。

/**
 * Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or
 * an activity), associated with this {@code ViewModelProvider}.
 * <p>
 * The created ViewModel is associated with the given scope and will be retained
 * as long as the scope is alive (e.g. if it is an activity, until it is
 * finished or process is killed).
 *
 * @param modelClass The class of the ViewModel to create an instance of it if it is not
 *                   present.
 * @param <T>        The type parameter for the ViewModel.
 * @return A ViewModel that is an instance of the given type {@code T}.
 */
@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;
}

看到這里就會(huì)發(fā)現(xiàn)ViewModelStore的緩存其實(shí)是通過(guò)NonConfigurationInstances的緩存來(lái)實(shí)現(xiàn)的,這樣就完成了Activity銷毀重建后ViewModel還保存原來(lái)的數(shù)據(jù)的過(guò)程,那么NonConfigurationInstances 是什么呢?如果有了解過(guò)使用在Activity中使用onRetainNonConfigurationInstance()保存緩存數(shù)據(jù),在onCreate()中通過(guò)getLastNonConfigurationInstance()恢復(fù)之前的數(shù)據(jù)狀態(tài)的同學(xué)可能會(huì)很熟悉這里的寫法,是的,這里FragmentActivity就是使用的這種方式來(lái)保存之前的ViewModelStore,看下FragmentActivity的onRetainNonConfigurationInstance()方法。

    /**
     * Retain all appropriate fragment state.  You can NOT
     * override this yourself!  Use {@link #onRetainCustomNonConfigurationInstance()}
     * if you want to retain your own state.
     */
    @Override
    public final Object onRetainNonConfigurationInstance() {
        if (mStopped) {
            doReallyStop(true);
        }

        Object custom = onRetainCustomNonConfigurationInstance();

        FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

        if (fragments == null && mViewModelStore == null && custom == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = mViewModelStore;//就是這里了,會(huì)把之前的VeiwmodelStroe存儲(chǔ)到NonConfigurationInstances中以供后續(xù)恢復(fù)使用
        nci.fragments = fragments;
        return nci;
    }

這里其實(shí)再次出現(xiàn)了一個(gè)問(wèn)題 onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()又是怎么恢復(fù)數(shù)據(jù)呢?...這個(gè)其實(shí)和Activity的啟動(dòng)流程相關(guān),這里也介紹一下吧,之后的內(nèi)容其實(shí)是Activity的內(nèi)容了,趁這次看ViwModel也跟著看了一遍,有了解過(guò)Activity啟動(dòng)流程的同學(xué)更容易理解的多,大家酌情觀看。

也不能從頭開始說(shuō)起,再?gòu)念^就要越扯越遠(yuǎn)了,就從ActivityThread.java中的scheduleLaunchActivity開始

        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

從ActivityThread.java中H(extents Handler)接收到LAUNCH_ACTIVITY,并且會(huì)接收ActivityClientRecord,其中會(huì)調(diào)用ActivityThread的handleLaunchActivity方法:

    //ActivityThread.java
    //沒有前后文的H中的handleMessage~~~
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
            //ActivityClientRecord 是apk進(jìn)程中一個(gè)Activity的代表,這個(gè)對(duì)象的activity成員引用真正的Activity組件,后面的都和它有關(guān)系
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");///這里~這里~
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
            ...
            Activity a = performLaunchActivity(r, customIntent);
        ...
    }

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
        if (activity != null) {
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                appContext.setOuterContext(activity);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config, //看到這個(gè)r.lastNonConfigurationInstances 就是在Activity方法中調(diào)用getLastNonConfigurationInstance()獲取到的Object了。
                        r.referrer, r.voiceInteractor, window, r.configCallback);
    ...
    }

注釋中的地方就是lastNonConfigurationInstances的賦值的地方,可能會(huì)發(fā)現(xiàn)在scheduleLaunchActivity并沒有對(duì)lastNonConfigurationInstances賦值,因?yàn)榈谝淮螁?dòng)Activity時(shí),這里其實(shí)就是null的,那么賦值的地方在哪里呢,既然是銷毀后會(huì)恢復(fù)數(shù)據(jù),追蹤發(fā)現(xiàn)在performDestroyActivity()也就是在調(diào)用onDestroy生命周期之前有這樣一段代碼

private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance) {
        ActivityClientRecord r = mActivities.get(token);
        ...無(wú)關(guān)代碼省略
            if (getNonConfigInstance) {
                try {
                    r.lastNonConfigurationInstances
                            = r.activity.retainNonConfigurationInstances();///就是這里出現(xiàn)了想要找的NonConfigurationInstances
                } catch (Exception e) {
                    if (!mInstrumentation.onException(r.activity, e)) {
                        throw new RuntimeException(
                                "Unable to retain activity "
                                + r.intent.getComponent().toShortString()
                                + ": " + e.toString(), e);
                    }
                }
            }
            try {
                r.activity.mCalled = false;
                mInstrumentation.callActivityOnDestroy(r.activity);
    ...無(wú)關(guān)代碼省略
        return r;
    }

在performDestroyActivity()調(diào)用了Activity.retainNonConfigurationInstances()方法了,所以邏輯切換回Activity中...

     /**
     * This method is similar to {@link #onRetainNonConfigurationInstance()} except that
     * it should return either a mapping from  child activity id strings to arbitrary objects,
     * or null.  This method is intended to be used by Activity framework subclasses that control a
     * set of child activities, such as ActivityGroup.  The same guarantees and restrictions apply
     * as for {@link #onRetainNonConfigurationInstance()}.  The default implementation returns null.
     */
    @Nullable
    HashMap<String,Object> onRetainNonConfigurationChildInstances() {
        return null;
    }

    NonConfigurationInstances retainNonConfigurationInstances() {
        Object activity = onRetainNonConfigurationInstance();///熟悉的代碼,原來(lái)的配方,和分析ActivityThread之前聯(lián)系起來(lái)了,在Activity中是空實(shí)現(xiàn),這里就是獲取子類的NonConfigurationInstance(),之前的例子就是的得FragmentActivity中的具體實(shí)現(xiàn),上文中已經(jīng)在分析ActivityThread.java已經(jīng)指出。
        HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
        FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

        // We're already stopped but we've been asked to retain.
        // Our fragments are taken care of but we need to mark the loaders for retention.
        // In order to do this correctly we need to restart the loaders first before
        // handing them off to the next activity.
        mFragments.doLoaderStart();
        mFragments.doLoaderStop(true);
        ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();

        if (activity == null && children == null && fragments == null && loaders == null
                && mVoiceInteractor == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.activity = activity;
        nci.children = children;
        nci.fragments = fragments;
        nci.loaders = loaders;
        if (mVoiceInteractor != null) {
            mVoiceInteractor.retainInstance();
            nci.voiceInteractor = mVoiceInteractor;
        }
        return nci;//這里返回的是Activity中的NonConfigurationInstances就保存在了ActivityClientRecord中了
    }

至此,ActivityClientRecord就不再深入了,可以看到在Activity中是以一個(gè)ArrayMap來(lái)保存Activity的記錄,記錄的就是Activity的狀態(tài),所以這里就實(shí)現(xiàn)了對(duì)NonConfigurationInstances的保存。


結(jié)語(yǔ):至此就基本看完了ViewModel在Activity中的使用和原理,在Fragment中的實(shí)現(xiàn)主要是使用setRetainInstance(true)的方式去保存,跟今天的分析也有關(guān)聯(lián),分析源碼的過(guò)程總是看著就有新的問(wèn)題,再次帶著問(wèn)題去解決會(huì)再次有不同的收獲,本文的理解也可能有偏差,如有錯(cuò)誤和想要交流的也歡迎指正溝通。

最后編輯于
?著作權(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)容