ViewModel相关生命周期的原理分析-之三

前言

前面介绍了ViewModel的生命周期,知道了其会在宿主activity或者fragment销毁时被销毁(config change造成的除外);如下图:


ViewModel lifecycle.png

但是没有深究其中的原理,虽然这并不影响我们的使用;但是为了知识的完成性,我们最好还是深入分析下其中的原理,同时,一些设计思想还是非常巧妙的,个人觉得是有很借鉴价值的。

分析

首先让我们回顾下ViewModel的获取方式

MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);

前面也说过,这其实是从创建的ViewModelProvider中得到ViewModelStore;而ViewModelStore是和宿主实例一一对应的;从ViewModelStore中获取相应classmodel对应的ViewModel实例;因此ViewModel生命周期其实是与ViewModelStore一致的;我们从这里入手进行分析,为什么config change(例如,屏幕旋转)造成的宿主销毁不会影响ViewModel的生命周期呢?

需要分开进行分析;

  1. before androidx support activity/fragment; 参考
    http://androidxref.com/8.1.0_r33/xref/frameworks/support/fragment/java/android/support/v4/app/FragmentActivity.java

  2. androidx support activity/fragment 参考
    http://androidxref.com/9.0.0_r3/xref/frameworks/support/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java

before androidx support activity/fragment宿主

当ViewModel的宿主是普通的activity或者fragment的时候,需要利用HolderFragment来保证config change时的生命周期,其原理如下

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

可见;对于normal宿主,会通过holderFragmentFor(activity)返回的HolderFragment来得到ViewModelStore实例;宿主和HolderFragment一一对应;

HolderFragment

宿主对应的HolderFragment持有相应的ViewModelStore

/**
 * @hide
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
    return sHolderFragmentManager.holderFragmentFor(activity); //返回activity宿主对应的HolderFragment 
}

@SuppressWarnings("WeakerAccess")
static class HolderFragmentManager {
    private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();  //activity对应的HolderFragment
    private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();

    private ActivityLifecycleCallbacks mActivityCallbacks =
            new EmptyActivityLifecycleCallbacks() {
                @Override
                public void onActivityDestroyed(Activity activity) {
                    HolderFragment fragment = mNotCommittedActivityHolders.remove(activity); //activity销毁的时候remove保存的HolderFragment
                    if (fragment != null) {
                        Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
                    }
                }
            };

    private boolean mActivityCallbacksIsAdded = false;

    private FragmentLifecycleCallbacks mParentDestroyedCallback =
            new FragmentLifecycleCallbacks() {
                @Override
                public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
                    super.onFragmentDestroyed(fm, parentFragment);
                    HolderFragment fragment = mNotCommittedFragmentHolders.remove(
                            parentFragment);
                    if (fragment != null) {
                        Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
                    }
                }
            };

    void holderFragmentCreated(Fragment holderFragment) {
        Fragment parentFragment = holderFragment.getParentFragment();
        if (parentFragment != null) {
            mNotCommittedFragmentHolders.remove(parentFragment);
            parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
                    mParentDestroyedCallback);
        } else {
            mNotCommittedActivityHolders.remove(holderFragment.getActivity());
        }
    }

    private static HolderFragment findHolderFragment(FragmentManager manager) {
        if (manager.isDestroyed()) {
            throw new IllegalStateException("Can't access ViewModels from onDestroy");
        }

        Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
        if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
            throw new IllegalStateException("Unexpected "
                    + "fragment instance was returned by HOLDER_TAG");
        }
        return (HolderFragment) fragmentByTag;
    }

    private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
        HolderFragment holder = new HolderFragment();
        fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
        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;
    }

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

主要逻辑都在HolderFragmentManager中;其主要原理是利用了嵌套fragment;需要用到的一些基础知识

嵌套fragmentManager

参考https://www.cnblogs.com/mengdd/p/5552721.html

嵌套Fragment的动态添加

在宿主fragment里调用getChildFragmentManager()
即可用它来向这个fragment内部添加fragments.
Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();
同样, 对于内部的fragment来说, getParentFragment() 方法可以获取到fragment的宿主fragment.

看起来HolderFragment 是嵌套子Fragment

getChildFragmentManager() 和 getFragmentManager()
  1. getChildFragmentManager()是fragment中的方法, 返回的是管理当前fragment内部子fragments的manager.
  2. getFragmentManager()在activity和fragment中都有.
    2.1 在activity中, 如果用的是v4 support库, 方法应该用getSupportFragmentManager(), 返回的是管理activity中fragments的manager;
    2.2 在fragment中, 还叫getFragmentManager(), 返回的是把自己加进来的那个manager.
    也即, 如果fragment在activity中, fragment.getFragmentManager()得到的是activity中管理fragments的那个manager.
    2.3 如果fragment是嵌套在另一个fragment中, fragment.getFragmentManager()得到的是它的parent的getChildFragmentManager().

总结就是: getFragmentManager()是本级别管理者, getChildFragmentManager()是下一级别管理者.
这实际上是一个树形管理结构.

setRetainInstance

参考https://blog.csdn.net/gaugamela/article/details/56280384

已保留的fragment不会随着activity一起被销毁; 相反,它会一直保留(进程不消亡的前提下),并在需要时原封不动地传递给新的Activity。

当设备配置发生变化时,FragmentManager首先销毁队列中fragment的视图(因为可能有更合适的匹配资源);

紧接着,FragmentManager将检查每个fragment的retainInstance属性值。如果retainInstance属性值为false,FragmentManager会立即销毁该fragment实例。
随后,为适应新的设备配置,新的Activity的新的FragmentManager会创建一个新的fragment及其视图。

setRetainInstance原理分析

Activity遇到config change时会先保存状态

4126    /**
4127     * Calls {@link Activity#onStop()} and {@link Activity#onSaveInstanceState(Bundle)}, and updates
4128     * the client record's state.
4129     * All calls to stop an activity must be done through this method to make sure that
4130     * {@link Activity#onSaveInstanceState(Bundle)} is also executed in the same call.
4131     */
4132    private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) {
4133        // Before P onSaveInstanceState was called before onStop, starting with P it's
4134        // called after. Before Honeycomb state was always saved before onPause.
4135        final boolean shouldSaveState = saveState && !r.activity.mFinished && r.state == null
4136                && !r.isPreHoneycomb(); //可见自己触发finish的时候不会saveState (调用到finish的时候)
4137        final boolean isPreP = r.isPreP();
4138        if (shouldSaveState && isPreP) {
4139            callActivityOnSaveInstanceState(r);
4140        }
4141
4142        try {
4143            r.activity.performStop(false /*preserveWindow*/, reason);
4144        } catch (SuperNotCalledException e) {
4145            throw e;
4146        } catch (Exception e) {
4147            if (!mInstrumentation.onException(r.activity, e)) {
4148                throw new RuntimeException(
4149                        "Unable to stop activity "
4150                                + r.intent.getComponent().toShortString()
4151                                + ": " + e.toString(), e);
4152            }
4153        }
4154        r.setState(ON_STOP);
4155
4156        if (shouldSaveState && !isPreP) {
4157            callActivityOnSaveInstanceState(r);
4158        }
4159    }
1435    /**
1436     * Perform calling of an activity's {@link Activity#onSaveInstanceState}
1437     * method.  The default implementation simply calls through to that method.
1438     *
1439     * @param activity The activity being saved.
1440     * @param outState The bundle to pass to the call.
1441     */
1442    public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
1443        activity.performSaveInstanceState(outState);
1444    }

activity stop时会根据情况调用onSaveInstanceState以保存状态

 /**
1574     * Called to retrieve per-instance state from an activity before being killed
1575     * so that the state can be restored in {@link #onCreate} or
1576     * {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
1577     * will be passed to both).
1578     *
1579     * <p>This method is called before an activity may be killed so that when it
1580     * comes back some time in the future it can restore its state.  For example,
1581     * if activity B is launched in front of activity A, and at some point activity
1582     * A is killed to reclaim resources, activity A will have a chance to save the
1583     * current state of its user interface via this method so that when the user
1584     * returns to activity A, the state of the user interface can be restored
1585     * via {@link #onCreate} or {@link #onRestoreInstanceState}.
1586     *
1587     * <p>Do not confuse this method with activity lifecycle callbacks such as
1588     * {@link #onPause}, which is always called when an activity is being placed
1589     * in the background or on its way to destruction, or {@link #onStop} which
1590     * is called before destruction.  One example of when {@link #onPause} and
1591     * {@link #onStop} is called and not this method is when a user navigates back
1592     * from activity B to activity A: there is no need to call {@link #onSaveInstanceState}
1593     * on B because that particular instance will never be restored, so the
1594     * system avoids calling it.  An example when {@link #onPause} is called and
1595     * not {@link #onSaveInstanceState} is when activity B is launched in front of activity A:
1596     * the system may avoid calling {@link #onSaveInstanceState} on activity A if it isn't
1597     * killed during the lifetime of B since the state of the user interface of
1598     * A will stay intact.
1599     *
1600     * <p>The default implementation takes care of most of the UI per-instance
1601     * state for you by calling {@link android.view.View#onSaveInstanceState()} on each
1602     * view in the hierarchy that has an id, and by saving the id of the currently
1603     * focused view (all of which is restored by the default implementation of
1604     * {@link #onRestoreInstanceState}).  If you override this method to save additional
1605     * information not captured by each individual view, you will likely want to
1606     * call through to the default implementation, otherwise be prepared to save
1607     * all of the state of each view yourself.
1608     *
1609     * <p>If called, this method will occur after {@link #onStop} for applications
1610     * targeting platforms starting with {@link android.os.Build.VERSION_CODES#P}.
1611     * For applications targeting earlier platform versions this method will occur
1612     * before {@link #onStop} and there are no guarantees about whether it will
1613     * occur before or after {@link #onPause}.
1614     *
1615     * @param outState Bundle in which to place your saved state.
1616     *
1617     * @see #onCreate
1618     * @see #onRestoreInstanceState
1619     * @see #onPause
1620     */
1621    protected void onSaveInstanceState(Bundle outState) {
1622        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
1623
1624        outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
1625        Parcelable p = mFragments.saveAllState();
1626        if (p != null) {
1627            outState.putParcelable(FRAGMENTS_TAG, p);
1628        }
1629        if (mAutoFillResetNeeded) {
1630            outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
1631            getAutofillManager().onSaveInstanceState(outState);
1632        }
1633        getApplication().dispatchActivitySaveInstanceState(this, outState);
1634    }

调用到FragmentController,FragmentManager来进行保存

112    /**
113     * Saves the state for all Fragments.
114     */
115    public Parcelable saveAllState() {
116        return mHost.mFragmentManager.saveAllState(); //activity持有的fragment controller
117    }
118
2699    Parcelable saveAllState() {
2700        // Make sure all pending operations have now been executed to get
2701        // our state update-to-date.
2702        forcePostponedTransactions();
2703        endAnimatingAwayFragments();
2704        execPendingActions();
2705
2706        mStateSaved = true;
2707        mSavedNonConfig = null;
2708
2709        if (mActive == null || mActive.size() <= 0) {
2710            return null;
2711        }
2712
2713        // First collect all active fragments.
2714        int N = mActive.size();
2715        FragmentState[] active = new FragmentState[N];
2716        boolean haveFragments = false;
2717        for (int i=0; i<N; i++) {
2718            Fragment f = mActive.valueAt(i);
2719            if (f != null) {
2720                if (f.mIndex < 0) {
2721                    throwException(new IllegalStateException(
2722                            "Failure saving state: active " + f
2723                            + " has cleared index: " + f.mIndex));
2724                }
2725
2726                haveFragments = true;
2727
2728                FragmentState fs = new FragmentState(f);
2729                active[i] = fs;
2730
2731                if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
2732                    fs.mSavedFragmentState = saveFragmentBasicState(f);
2733
2734                    if (f.mTarget != null) {
2735                        if (f.mTarget.mIndex < 0) {
2736                            throwException(new IllegalStateException(
2737                                    "Failure saving state: " + f
2738                                    + " has target not in fragment manager: " + f.mTarget));
2739                        }
2740                        if (fs.mSavedFragmentState == null) {
2741                            fs.mSavedFragmentState = new Bundle();
2742                        }
2743                        putFragment(fs.mSavedFragmentState,
2744                                FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
2745                        if (f.mTargetRequestCode != 0) {
2746                            fs.mSavedFragmentState.putInt(
2747                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
2748                                    f.mTargetRequestCode);
2749                        }
2750                    }
2751
2752                } else {
2753                    fs.mSavedFragmentState = f.mSavedFragmentState;
2754                }
2755
2756                if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
2757                        + fs.mSavedFragmentState);
2758            }
2759        }
2760
2761        if (!haveFragments) {
2762            if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
2763            return null;
2764        }
2765
2766        int[] added = null;
2767        BackStackState[] backStack = null;
2768
2769        // Build list of currently added fragments.
2770        N = mAdded.size();
2771        if (N > 0) {
2772            added = new int[N];
2773            for (int i=0; i<N; i++) {
2774                added[i] = mAdded.get(i).mIndex;
2775                if (added[i] < 0) {
2776                    throwException(new IllegalStateException(
2777                            "Failure saving state: active " + mAdded.get(i)
2778                            + " has cleared index: " + added[i]));
2779                }
2780                if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
2781                        + ": " + mAdded.get(i));
2782            }
2783        }
2784
2785        // Now save back stack.
2786        if (mBackStack != null) {
2787            N = mBackStack.size();
2788            if (N > 0) {
2789                backStack = new BackStackState[N];
2790                for (int i=0; i<N; i++) {
2791                    backStack[i] = new BackStackState(this, mBackStack.get(i));
2792                    if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
2793                            + ": " + mBackStack.get(i));
2794                }
2795            }
2796        }
2797
2798        FragmentManagerState fms = new FragmentManagerState();
2799        fms.mActive = active;
2800        fms.mAdded = added;
2801        fms.mBackStack = backStack;
2802        fms.mNextFragmentIndex = mNextFragmentIndex;
2803        if (mPrimaryNav != null) {
2804            fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
2805        }
2806        saveNonConfig();
2807        return fms;
2808    }

对所有active fragment和嵌套的fragment进行识别;如果mRetainInstance = true;则用FragmentManagerNonConfig进行保存

2604    void saveNonConfig() {
2605        ArrayList<Fragment> fragments = null;
2606        ArrayList<FragmentManagerNonConfig> childFragments = null;
2607        if (mActive != null) {
2608            for (int i=0; i<mActive.size(); i++) {
2609                Fragment f = mActive.valueAt(i);
2610                if (f != null) {
2611                    if (f.mRetainInstance) {
2612                        if (fragments == null) {
2613                            fragments = new ArrayList<>();
2614                        }
2615                        fragments.add(f);
2616                        f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
2617                        if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
2618                    }
2619                    FragmentManagerNonConfig child;
2620                    if (f.mChildFragmentManager != null) {
2621                        f.mChildFragmentManager.saveNonConfig();
2622                        child = f.mChildFragmentManager.mSavedNonConfig;
2623                    } else {
2624                        // f.mChildNonConfig may be not null, when the parent fragment is
2625                        // in the backstack.
2626                        child = f.mChildNonConfig;
2627                    }
2628
2629                    if (childFragments == null && child != null) {
2630                        childFragments = new ArrayList<>(mActive.size());
2631                        for (int j = 0; j < i; j++) {
2632                            childFragments.add(null);
2633                        }
2634                    }
2635
2636                    if (childFragments != null) {
2637                        childFragments.add(child);
2638                    }
2639                }
2640            }
2641        }
2642        if (fragments == null && childFragments == null) {
2643            mSavedNonConfig = null;
2644        } else {
2645            mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments);
2646        }
2647    }

将fragment对象持有住

可以看到保存fragment对象的大致逻辑; 从Activity的生命周期状态中触发,调用FragmentController->FragmentManager从而将设置了setRetainInstance(true)的fragment的相关fragment保存起来;这样config change时fragment不会执行到onDestroy; 对于HolderFragment而言,不会执行到其onDestory方法,ViewModelStore及其对应ViewModel均会得以保留

@Override
    public void onDestroy() {
        super.onDestroy();
        mViewModelStore.clear();
    }

还原的是后也是相似的路径还原的,将FragmentManagerNonConfig保存的对象还原出来,添加到相关队列里

2810    void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
2811        // If there is no saved state at all, then there can not be
2812        // any nonConfig fragments either, so that is that.
2813        if (state == null) return;
2814        FragmentManagerState fms = (FragmentManagerState)state;
2815        if (fms.mActive == null) return;
2816
2817        List<FragmentManagerNonConfig> childNonConfigs = null;
2818
2819        // First re-attach any non-config instances we are retaining back
2820        // to their saved state, so we don't try to instantiate them again.
2821        if (nonConfig != null) {
2822            List<Fragment> nonConfigFragments = nonConfig.getFragments();
2823            childNonConfigs = nonConfig.getChildNonConfigs();
2824            final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
2825            for (int i = 0; i < count; i++) {
2826                Fragment f = nonConfigFragments.get(i);
2827                if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
2828                int index = 0; // index of f in fms.mActive
2829                while (index < fms.mActive.length && fms.mActive[index].mIndex != f.mIndex) {
2830                    index++;
2831                }
2832                if (index == fms.mActive.length) {
2833                    throwException(new IllegalStateException("Could not find active fragment "
2834                            + "with index " + f.mIndex));
2835                }
2836                FragmentState fs = fms.mActive[index];
2837                fs.mInstance = f;
2838                f.mSavedViewState = null;
2839                f.mBackStackNesting = 0;
2840                f.mInLayout = false;
2841                f.mAdded = false;
2842                f.mTarget = null;
2843                if (fs.mSavedFragmentState != null) {
2844                    fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
2845                    f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
2846                            FragmentManagerImpl.VIEW_STATE_TAG);
2847                    f.mSavedFragmentState = fs.mSavedFragmentState;
2848                }
2849            }
2850        }
2851
2852        // Build the full list of active fragments, instantiating them from
2853        // their saved state.
2854        mActive = new SparseArray<>(fms.mActive.length);
2855        for (int i=0; i<fms.mActive.length; i++) {
2856            FragmentState fs = fms.mActive[i];
2857            if (fs != null) {
2858                FragmentManagerNonConfig childNonConfig = null;
2859                if (childNonConfigs != null && i < childNonConfigs.size()) {
2860                    childNonConfig = childNonConfigs.get(i);
2861                }
2862                Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig);
2863                if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
2864                mActive.put(f.mIndex, f);
2865                // Now that the fragment is instantiated (or came from being
2866                // retained above), clear mInstance in case we end up re-restoring
2867                // from this FragmentState again.
2868                fs.mInstance = null;
2869            }
2870        }
2871
2872        // Update the target of all retained fragments.
2873        if (nonConfig != null) {
2874            List<Fragment> nonConfigFragments = nonConfig.getFragments();
2875            final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
2876            for (int i = 0; i < count; i++) {
2877                Fragment f = nonConfigFragments.get(i);
2878                if (f.mTargetIndex >= 0) {
2879                    f.mTarget = mActive.get(f.mTargetIndex);
2880                    if (f.mTarget == null) {
2881                        Log.w(TAG, "Re-attaching retained fragment " + f
2882                                + " target no longer exists: " + f.mTargetIndex);
2883                        f.mTarget = null;
2884                    }
2885                }
2886            }
2887        }
2888
2889        // Build the list of currently added fragments.
2890        mAdded.clear();
2891        if (fms.mAdded != null) {
2892            for (int i=0; i<fms.mAdded.length; i++) {
2893                Fragment f = mActive.get(fms.mAdded[i]);
2894                if (f == null) {
2895                    throwException(new IllegalStateException(
2896                            "No instantiated fragment for index #" + fms.mAdded[i]));
2897                }
2898                f.mAdded = true;
2899                if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
2900                if (mAdded.contains(f)) {
2901                    throw new IllegalStateException("Already added!");
2902                }
2903                synchronized (mAdded) {
2904                    mAdded.add(f);
2905                }
2906            }
2907        }
2908
2909        // Build the back stack.
2910        if (fms.mBackStack != null) {
2911            mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
2912            for (int i=0; i<fms.mBackStack.length; i++) {
2913                BackStackRecord bse = fms.mBackStack[i].instantiate(this);
2914                if (DEBUG) {
2915                    Log.v(TAG, "restoreAllState: back stack #" + i
2916                        + " (index " + bse.mIndex + "): " + bse);
2917                    LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
2918                    PrintWriter pw = new FastPrintWriter(logw, false, 1024);
2919                    bse.dump("  ", pw, false);
2920                    pw.flush();
2921                }
2922                mBackStack.add(bse);
2923                if (bse.mIndex >= 0) {
2924                    setBackStackIndex(bse.mIndex, bse);
2925                }
2926            }
2927        } else {
2928            mBackStack = null;
2929        }
2930
2931        if (fms.mPrimaryNavActiveIndex >= 0) {
2932            mPrimaryNav = mActive.get(fms.mPrimaryNavActiveIndex);
2933        }
2934
2935        mNextFragmentIndex = fms.mNextFragmentIndex;
2936    }

HolderFragment相关

构造函数

public HolderFragment() {
    setRetainInstance(true);
}

保持了屏幕旋转时不会调用onDestroy; 同时又持有 ViewModelStore实例对象,从而维护了其生命周期

那么activity或者fragment作为宿主如何和HolderFragment对应的呢?

normal activity bind HolderFragment

首先看activity的holderFragmentFor(activity)

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


HolderFragment holderFragmentFor(FragmentActivity activity) {
    FragmentManager fm = activity.getSupportFragmentManager();
    HolderFragment holder = findHolderFragment(fm); //在activity对应的FragmentManager找到对应的fragment(实现activity宿主和HolderFragment的一一对应)
    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); //如果没找到就通过FragmentManager添加一个
    mNotCommittedActivityHolders.put(activity, holder); //并且存储一个map 
    return holder;
}

private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
    HolderFragment holder = new HolderFragment();
    fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
    return holder;
}

相当于通过fragmentManager.add添加一个无View的HolderFragment,其持有ViewModelStore的引用,并将mRetainInstance置为true,保证了config change时的生命周期

normal fragment bind HolderFragment

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是宿主fragment的嵌套子fragment;

对应关系

宿主activity/fragment怎么保持和HolderFragment实例的对应关系呢?

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    sHolderFragmentManager.holderFragmentCreated(this);
}

//相当于做清理工作; 每次开始前先把清理工作做了
void holderFragmentCreated(Fragment holderFragment) {
    Fragment parentFragment = holderFragment.getParentFragment();
    if (parentFragment != null) { //fragment作为宿主的情况
        mNotCommittedFragmentHolders.remove(parentFragment);
        parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
                mParentDestroyedCallback);
    } else {
        mNotCommittedActivityHolders.remove(holderFragment.getActivity());
    }
}

通过mNotCommittedActivityHolders和mNotCommittedFragmentHolders进行映射,相当于一个backup缓存;HolderFragment的onCreate会进行清理(config change还原时不会走到HolderFragment的onCreate);


fragment lifecycle.png
private ActivityLifecycleCallbacks mActivityCallbacks =
                new EmptyActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityDestroyed(Activity activity) {
                        HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
                        }
                    }
                };

        private boolean mActivityCallbacksIsAdded = false;

        private FragmentLifecycleCallbacks mParentDestroyedCallback =
                new FragmentLifecycleCallbacks() {
                    @Override
                    public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
                        super.onFragmentDestroyed(fm, parentFragment);
                        HolderFragment fragment = mNotCommittedFragmentHolders.remove(
                                parentFragment);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
                        }
                    }
                };

监听到宿主destory的时候会进行清理,宿主销毁时要将对应的映射也删去,清空缓存;

到此为止我们就大致明白了normal activity/fragment作为宿主时是如何保证ViewModel的生命周期的;不得不说这个设计还是很巧妙的,一个简单的fragment就实现了对ViewModelStore的维护; (我觉得这个思路值得我们借鉴,可以保存ViewModel,那是否可以保存其他东西呢? )

androidx support activity/fragment宿主 (sdkversion>=28)

因为support类型的宿主实现了ViewModelStoreOwner;所以就无需HolderFragment辅助了,而是系统内部已经帮我们实现好了;

public static ViewModelStore of(@NonNull FragmentActivity activity) {
    if (activity instanceof ViewModelStoreOwner) {
        return ((ViewModelStoreOwner) activity).getViewModelStore();
    }
    return holderFragmentFor(activity).getViewModelStore();
}

((ViewModelStoreOwner) activity).getViewModelStore();注意这里,直接从宿主中getViewModelStore成员变量,那么是如何保存的呢?

activity (FragmentActivity)

398    /**
399     * Destroy all fragments.
400     */
401    @Override
402    protected void onDestroy() {
403        super.onDestroy();
404
405        if (mViewModelStore != null && !isChangingConfigurations()) {
406            mViewModelStore.clear(); //对于config change造成的destory,不销毁
407        }
408
409        mFragments.dispatchDestroy(); //让管理的fragment destory 
410    }
/**
 * Check to see whether this activity is in the process of being destroyed in order to be
 * recreated with a new configuration. This is often used in
 * {@link #onStop} to determine whether the state needs to be cleaned up or will be passed
 * on to the next instance of the activity via {@link #onRetainNonConfigurationInstance()}.
 *
 * @return If the activity is being torn down in order to be recreated with a new configuration,
 * returns true; else returns false.
 */
public boolean isChangingConfigurations() {
    return mChangingConfigurations;
}

http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java#2497
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java#2734
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/ActivityThread.java#4595

ensureActivityConfiguration->relaunchActivityLocked-----binder call----------->handleRelaunchActivity (监听到config变化,走relaunch逻辑,将mChangingConfigurations置为true,这样Activity的ViewModelStore不会clear)
r.activity.mChangingConfigurations = true;

这里会将mViewModelStore保存下来

552    /**
553     * Retain all appropriate fragment state.  You can NOT
554     * override this yourself!  Use {@link #onRetainCustomNonConfigurationInstance()}
555     * if you want to retain your own state.
556     */
557    @Override
558    public final Object onRetainNonConfigurationInstance() {
559        Object custom = onRetainCustomNonConfigurationInstance();
560
561        FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
562
563        if (fragments == null && mViewModelStore == null && custom == null) {
564            return null;
565        }
566
567        NonConfigurationInstances nci = new NonConfigurationInstances();
568        nci.custom = custom;
569        nci.viewModelStore = mViewModelStore;
570        nci.fragments = fragments;
571        return nci;
572    }

会在activity 要被destory的时候将需要的东西保存下来

4410    /** Core implementation of activity destroy call. */
4411    ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
4412            int configChanges, boolean getNonConfigInstance, String reason) {
4413        ActivityClientRecord r = mActivities.get(token);
4414        Class<? extends Activity> activityClass = null;
4415        if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
4416        if (r != null) {
4417            activityClass = r.activity.getClass();
4418            r.activity.mConfigChangeFlags |= configChanges;
4419            if (finishing) {
4420                r.activity.mFinished = true;
4421            }
4422
4423            performPauseActivityIfNeeded(r, "destroy");
4424
4425            if (!r.stopped) {
4426                callActivityOnStop(r, false /* saveState */, "destroy");
4427            }
4428            if (getNonConfigInstance) {
4429                try {
4430                    r.lastNonConfigurationInstances
4431                            = r.activity.retainNonConfigurationInstances();
4432                } catch (Exception e) {
4433                    if (!mInstrumentation.onException(r.activity, e)) {
4434                        throw new RuntimeException(
4435                                "Unable to retain activity "
4436                                + r.intent.getComponent().toShortString()
4437                                + ": " + e.toString(), e);
4438                    }
4439                }
4440            }
4441            try {
4442                r.activity.mCalled = false;
4443                mInstrumentation.callActivityOnDestroy(r.activity);
4444                if (!r.activity.mCalled) {
4445                    throw new SuperNotCalledException(
4446                        "Activity " + safeToComponentShortString(r.intent) +
4447                        " did not call through to super.onDestroy()");
4448                }
4449                if (r.window != null) {
4450                    r.window.closeAllPanels();
4451                }
4452            } catch (SuperNotCalledException e) {
4453                throw e;
4454            } catch (Exception e) {
4455                if (!mInstrumentation.onException(r.activity, e)) {
4456                    throw new RuntimeException(
4457                            "Unable to destroy activity " + safeToComponentShortString(r.intent)
4458                            + ": " + e.toString(), e);
4459                }
4460            }
4461            r.setState(ON_DESTROY);
4462        }
4463        mActivities.remove(token);
4464        StrictMode.decrementExpectedActivityCount(activityClass);
4465        return r;
4466    }

然后再onCreate的时候重新还原; mViewModelStore对象还原了,且前面又没有清掉里面保存的ViewModel对象,这样就做到了config change但是不销毁ViewModel;

317    /**
318     * Perform initialization of all fragments.
319     */
320    @SuppressWarnings("deprecation")
321    @Override
322    protected void onCreate(@Nullable Bundle savedInstanceState) {
323        mFragments.attachHost(null /*parent*/);
324
325        super.onCreate(savedInstanceState);
326
327        NonConfigurationInstances nc =
328                (NonConfigurationInstances) getLastNonConfigurationInstance();
329        if (nc != null) {
330            mViewModelStore = nc.viewModelStore;
331        }
332        if (savedInstanceState != null) {
333            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
334            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
335
336            // Check if there are any pending onActivityResult calls to descendent Fragments.
337            if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
338                mNextCandidateRequestIndex =
339                        savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
340                int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
341                String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
342                if (requestCodes == null || fragmentWhos == null ||
343                            requestCodes.length != fragmentWhos.length) {
344                    Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
345                } else {
346                    mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
347                    for (int i = 0; i < requestCodes.length; i++) {
348                        mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
349                    }
350                }
351            }
352        }
353
354        if (mPendingFragmentActivityResults == null) {
355            mPendingFragmentActivityResults = new SparseArrayCompat<>();
356            mNextCandidateRequestIndex = 0;
357        }
358
359        mFragments.dispatchCreate();
360    }

activity还原过程

2304    /**
2305     * Retrieve the non-configuration instance data that was previously
2306     * returned by {@link #onRetainNonConfigurationInstance()}.  This will
2307     * be available from the initial {@link #onCreate} and
2308     * {@link #onStart} calls to the new instance, allowing you to extract
2309     * any useful dynamic state from the previous instance.
2310     *
2311     * <p>Note that the data you retrieve here should <em>only</em> be used
2312     * as an optimization for handling configuration changes.  You should always
2313     * be able to handle getting a null pointer back, and an activity must
2314     * still be able to restore itself to its previous state (through the
2315     * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
2316     * function returns null.
2317     *
2318     * <p><strong>Note:</strong> For most cases you should use the {@link Fragment} API
2319     * {@link Fragment#setRetainInstance(boolean)} instead; this is also
2320     * available on older platforms through the Android support libraries.
2321     *
2322     * @return the object previously returned by {@link #onRetainNonConfigurationInstance()}
2323     */
2324    @Nullable
2325    public Object getLastNonConfigurationInstance() {
2326        return mLastNonConfigurationInstances != null
2327                ? mLastNonConfigurationInstances.activity : null;
2328    }

Fragment

如果宿主是fragment

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

也就是说就算调用了onDestory;只要mStateSaved = true,也不会清掉mViewModelStore

FragmentManager saveAllState
2936    Parcelable saveAllState() {
2937        // Make sure all pending operations have now been executed to get
2938        // our state update-to-date.
2939        forcePostponedTransactions();
2940        endAnimatingAwayFragments();
2941        execPendingActions();
2942
2943        mStateSaved = true;
2944        mSavedNonConfig = null;
2945
2946        if (mActive == null || mActive.size() <= 0) {
2947            return null;
2948        }
2949
2950        // First collect all active fragments.
2951        int N = mActive.size();
2952        FragmentState[] active = new FragmentState[N];
2953        boolean haveFragments = false;
2954        for (int i=0; i<N; i++) {
2955            Fragment f = mActive.valueAt(i);
2956            if (f != null) {
2957                if (f.mIndex < 0) {
2958                    throwException(new IllegalStateException(
2959                            "Failure saving state: active " + f
2960                            + " has cleared index: " + f.mIndex));
2961                }
2962
2963                haveFragments = true;
2964
2965                FragmentState fs = new FragmentState(f);
2966                active[i] = fs;
2967
2968                if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
2969                    fs.mSavedFragmentState = saveFragmentBasicState(f);
2970
2971                    if (f.mTarget != null) {
2972                        if (f.mTarget.mIndex < 0) {
2973                            throwException(new IllegalStateException(
2974                                    "Failure saving state: " + f
2975                                    + " has target not in fragment manager: " + f.mTarget));
2976                        }
2977                        if (fs.mSavedFragmentState == null) {
2978                            fs.mSavedFragmentState = new Bundle();
2979                        }
2980                        putFragment(fs.mSavedFragmentState,
2981                                FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
2982                        if (f.mTargetRequestCode != 0) {
2983                            fs.mSavedFragmentState.putInt(
2984                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
2985                                    f.mTargetRequestCode);
2986                        }
2987                    }
2988
2989                } else {
2990                    fs.mSavedFragmentState = f.mSavedFragmentState;
2991                }
2992
2993                if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
2994                        + fs.mSavedFragmentState);
2995            }
2996        }
2997
2998        if (!haveFragments) {
2999            if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
3000            return null;
3001        }
3002
3003        int[] added = null;
3004        BackStackState[] backStack = null;
3005
3006        // Build list of currently added fragments.
3007        N = mAdded.size();
3008        if (N > 0) {
3009            added = new int[N];
3010            for (int i = 0; i < N; i++) {
3011                added[i] = mAdded.get(i).mIndex;
3012                if (added[i] < 0) {
3013                    throwException(new IllegalStateException(
3014                            "Failure saving state: active " + mAdded.get(i)
3015                            + " has cleared index: " + added[i]));
3016                }
3017                if (DEBUG) {
3018                    Log.v(TAG, "saveAllState: adding fragment #" + i
3019                            + ": " + mAdded.get(i));
3020                }
3021            }
3022        }
3023
3024        // Now save back stack.
3025        if (mBackStack != null) {
3026            N = mBackStack.size();
3027            if (N > 0) {
3028                backStack = new BackStackState[N];
3029                for (int i=0; i<N; i++) {
3030                    backStack[i] = new BackStackState(mBackStack.get(i));
3031                    if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
3032                            + ": " + mBackStack.get(i));
3033                }
3034            }
3035        }
3036
3037        FragmentManagerState fms = new FragmentManagerState();
3038        fms.mActive = active;
3039        fms.mAdded = added;
3040        fms.mBackStack = backStack;
3041        if (mPrimaryNav != null) {
3042            fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
3043        }
3044        fms.mNextFragmentIndex = mNextFragmentIndex;
3045        saveNonConfig();
3046        return fms;
3047    }
2829    void saveNonConfig() {
2830        ArrayList<Fragment> fragments = null;
2831        ArrayList<FragmentManagerNonConfig> childFragments = null;
2832        ArrayList<ViewModelStore> viewModelStores = null;
2833        if (mActive != null) {
2834            for (int i=0; i<mActive.size(); i++) {
2835                Fragment f = mActive.valueAt(i);
2836                if (f != null) {
2837                    if (f.mRetainInstance) {
2838                        if (fragments == null) {
2839                            fragments = new ArrayList<Fragment>();
2840                        }
2841                        fragments.add(f);
2842                        f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
2843                        if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
2844                    }
2845                    FragmentManagerNonConfig child;
2846                    if (f.mChildFragmentManager != null) {
2847                        f.mChildFragmentManager.saveNonConfig();
2848                        child = f.mChildFragmentManager.mSavedNonConfig;
2849                    } else {
2850                        // f.mChildNonConfig may be not null, when the parent fragment is
2851                        // in the backstack.
2852                        child = f.mChildNonConfig;
2853                    }
2854
2855                    if (childFragments == null && child != null) {
2856                        childFragments = new ArrayList<>(mActive.size());
2857                        for (int j = 0; j < i; j++) {
2858                            childFragments.add(null);
2859                        }
2860                    }
2861
2862                    if (childFragments != null) {
2863                        childFragments.add(child);
2864                    }
2865                    if (viewModelStores == null && f.mViewModelStore != null) {
2866                        viewModelStores = new ArrayList<>(mActive.size());
2867                        for (int j = 0; j < i; j++) {
2868                            viewModelStores.add(null);
2869                        }
2870                    }
2871
2872                    if (viewModelStores != null) {
2873                        viewModelStores.add(f.mViewModelStore);
2874                    }
2875                }
2876            }
2877        }
2878        if (fragments == null && childFragments == null && viewModelStores == null) {
2879            mSavedNonConfig = null;
2880        } else {
2881            mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments,
2882                    viewModelStores); //将要保存的东西都存到FragmentManagerNonConfig,相比上面多加了一个mViewModelStore
                    //包括三部分:不被销毁的Fragment集合(通过setRetainInstance(true)),所有子Fragment中需要保存的数据以及所有的Fragment中的ViewModelStore
2883        }
2884    }

所以宿主fragment不设定setRetainInstance也没关系,因为fragment销毁了但是其mViewModelStore并没有销毁;而是被保存起来了

fragment还原ViewModel过程

1461    /**
1462     * Called to do initial creation of a fragment.  This is called after
1463     * {@link #onAttach(Activity)} and before
1464     * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
1465     *
1466     * <p>Note that this can be called while the fragment's activity is
1467     * still in the process of being created.  As such, you can not rely
1468     * on things like the activity's content view hierarchy being initialized
1469     * at this point.  If you want to do work once the activity itself is
1470     * created, see {@link #onActivityCreated(Bundle)}.
1471     *
1472     * <p>Any restored child fragments will be created before the base
1473     * <code>Fragment.onCreate</code> method returns.</p>
1474     *
1475     * @param savedInstanceState If the fragment is being re-created from
1476     * a previous saved state, this is the state.
1477     */
1478    @CallSuper
1479    public void onCreate(@Nullable Bundle savedInstanceState) {
1480        mCalled = true;
1481        restoreChildFragmentState(savedInstanceState);
1482        if (mChildFragmentManager != null
1483                && !mChildFragmentManager.isStateAtLeast(Fragment.CREATED)) {
1484            mChildFragmentManager.dispatchCreate();
1485        }
1486    }
1488    /**
1489     * Restore the state of the child FragmentManager. Called by either
1490     * {@link #onCreate(Bundle)} for non-retained instance fragments or by
1491     * {@link FragmentManagerImpl#moveToState(Fragment, int, int, int, boolean)}
1492     * for retained instance fragments.
1493     *
1494     * <p><strong>Postcondition:</strong> if there were child fragments to restore,
1495     * the child FragmentManager will be instantiated and brought to the {@link #CREATED} state.
1496     * </p>
1497     *
1498     * @param savedInstanceState the savedInstanceState potentially containing fragment info
1499     */
1500    void restoreChildFragmentState(@Nullable Bundle savedInstanceState) {
1501        if (savedInstanceState != null) {
1502            Parcelable p = savedInstanceState.getParcelable(
1503                    FragmentActivity.FRAGMENTS_TAG);
1504            if (p != null) {
1505                if (mChildFragmentManager == null) {
1506                    instantiateChildFragmentManager();
1507                }
1508                mChildFragmentManager.restoreAllState(p, mChildNonConfig);
1509                mChildNonConfig = null;
1510                mChildFragmentManager.dispatchCreate();
1511            }
1512        }
1513    }
3049    void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
3050        // If there is no saved state at all, then there can not be
3051        // any nonConfig fragments either, so that is that.
3052        if (state == null) return;
3053        FragmentManagerState fms = (FragmentManagerState)state;
3054        if (fms.mActive == null) return;
3055
3056        List<FragmentManagerNonConfig> childNonConfigs = null;
3057        List<ViewModelStore> viewModelStores = null;
3058
3059        // First re-attach any non-config instances we are retaining back
3060        // to their saved state, so we don't try to instantiate them again.
3061        if (nonConfig != null) {
3062            List<Fragment> nonConfigFragments = nonConfig.getFragments();
3063            childNonConfigs = nonConfig.getChildNonConfigs();
3064            viewModelStores = nonConfig.getViewModelStores();
3065            final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
3066            for (int i = 0; i < count; i++) {
3067                Fragment f = nonConfigFragments.get(i);
3068                if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
3069                int index = 0; // index into fms.mActive
3070                while (index < fms.mActive.length && fms.mActive[index].mIndex != f.mIndex) {
3071                    index++;
3072                }
3073                if (index == fms.mActive.length) {
3074                    throwException(new IllegalStateException("Could not find active fragment "
3075                            + "with index " + f.mIndex));
3076                }
3077                FragmentState fs = fms.mActive[index];
3078                fs.mInstance = f;
3079                f.mSavedViewState = null;
3080                f.mBackStackNesting = 0;
3081                f.mInLayout = false;
3082                f.mAdded = false;
3083                f.mTarget = null;
3084                if (fs.mSavedFragmentState != null) {
3085                    fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
3086                    f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
3087                            FragmentManagerImpl.VIEW_STATE_TAG);
3088                    f.mSavedFragmentState = fs.mSavedFragmentState;
3089                }
3090            }
3091        }
3092
3093        // Build the full list of active fragments, instantiating them from
3094        // their saved state.
3095        mActive = new SparseArray<>(fms.mActive.length);
3096        for (int i=0; i<fms.mActive.length; i++) {
3097            FragmentState fs = fms.mActive[i];
3098            if (fs != null) {
3099                FragmentManagerNonConfig childNonConfig = null;
3100                if (childNonConfigs != null && i < childNonConfigs.size()) {
3101                    childNonConfig = childNonConfigs.get(i);
3102                }
3103                ViewModelStore viewModelStore = null;
3104                if (viewModelStores != null && i < viewModelStores.size()) {
3105                    viewModelStore = viewModelStores.get(i);
3106                }
3107                Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig,
3108                        viewModelStore);
3109                if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
3110                mActive.put(f.mIndex, f);
3111                // Now that the fragment is instantiated (or came from being
3112                // retained above), clear mInstance in case we end up re-restoring
3113                // from this FragmentState again.
3114                fs.mInstance = null;
3115            }
3116        }
3117
3118        // Update the target of all retained fragments.
3119        if (nonConfig != null) {
3120            List<Fragment> nonConfigFragments = nonConfig.getFragments();
3121            final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
3122            for (int i = 0; i < count; i++) {
3123                Fragment f = nonConfigFragments.get(i);
3124                if (f.mTargetIndex >= 0) {
3125                    f.mTarget = mActive.get(f.mTargetIndex);
3126                    if (f.mTarget == null) {
3127                        Log.w(TAG, "Re-attaching retained fragment " + f
3128                                + " target no longer exists: " + f.mTargetIndex);
3129                    }
3130                }
3131            }
3132        }
3133
3134        // Build the list of currently added fragments.
3135        mAdded.clear();
3136        if (fms.mAdded != null) {
3137            for (int i=0; i<fms.mAdded.length; i++) {
3138                Fragment f = mActive.get(fms.mAdded[i]);
3139                if (f == null) {
3140                    throwException(new IllegalStateException(
3141                            "No instantiated fragment for index #" + fms.mAdded[i]));
3142                }
3143                f.mAdded = true;
3144                if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
3145                if (mAdded.contains(f)) {
3146                    throw new IllegalStateException("Already added!");
3147                }
3148                synchronized (mAdded) {
3149                    mAdded.add(f);
3150                }
3151            }
3152        }
3153
3154        // Build the back stack.
3155        if (fms.mBackStack != null) {
3156            mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
3157            for (int i=0; i<fms.mBackStack.length; i++) {
3158                BackStackRecord bse = fms.mBackStack[i].instantiate(this);
3159                if (DEBUG) {
3160                    Log.v(TAG, "restoreAllState: back stack #" + i
3161                        + " (index " + bse.mIndex + "): " + bse);
3162                    LogWriter logw = new LogWriter(TAG);
3163                    PrintWriter pw = new PrintWriter(logw);
3164                    bse.dump("  ", pw, false);
3165                    pw.close();
3166                }
3167                mBackStack.add(bse);
3168                if (bse.mIndex >= 0) {
3169                    setBackStackIndex(bse.mIndex, bse);
3170                }
3171            }
3172        } else {
3173            mBackStack = null;
3174        }
3175
3176        if (fms.mPrimaryNavActiveIndex >= 0) {
3177            mPrimaryNav = mActive.get(fms.mPrimaryNavActiveIndex);
3178        }i
3179        this.mNextFragmentIndex = fms.mNextFragmentIndex;
3180    }

这里其实看起来复杂,但和androidx 的Activity保存ViewModelStore的原理类似;都是让他正常销毁;然后保存

总结

本问总结了ViewModel在config change时保持生命周期的相关原理;分为两种情况:

  1. before androidx support activity/fragment
    利用无View的HolderFragment,使用setRetainInstance(true)保证其在config change时不被销毁;这个思路值得我们借鉴
  2. androidx support activity/fragment
    在系统层进行了适配,无需HolderFragment接入了,其原理是config change正常执行销毁工作,只不过在再次relaunch时还原;

虽然保存/还原的代码看上去类似,但其实是两种不同的原理,尤其要注意利用HolderFragment的兼容性适配工作,其实一种巧妙的设计思路,只有对aosp源码,activity/fragment生命周期,交互有较深了解的人才能进行这样巧妙的设计,值得我们学习

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 前言Fragment想必大家不陌生吧,在日常开发中,对于Fragment的使用也很频繁,现在主流的APP中,基本的...
    hahaoop阅读 962评论 0 15
  • 介绍 ViewModel属于ACC框架组件之一,用以解决数据持久与共享问题,此外,也将数据的相关行为从UI中分离出...
    MxsQ阅读 7,167评论 0 7
  • Fragment 描述:   翻译可以译为:碎片、片段,Android 3.0开始引入fragments 的概念;...
    Lost_Robot阅读 1,636评论 0 11
  • (七 律) 流金岁月不轩昂, 岁月迁延热血扬。 理想追求挥梦笔, 感恩拥有乐心房。 葵花微笑朝阳爱...
    清泉玉阅读 1,387评论 17 73
  • 有多少人活着, 可他的心已死去, 有多少人死去, 可他的心还活着; 活着不是为了死去, 有多少人行尸走肉的活着, ...
    一念斬千愁阅读 124评论 0 1