Fragment(一)

Android知识总结

一、Fragment 的使用

实现很简单,创建一个的布局,然后在 Activity 里点击时替换 Fragment。

mFragmentManager = getSupportFragmentManager();
mFragmentManager.beginTransaction()
 .replace(R.id.fl_content, fragment)
 .commitAllowingStateLoss();

代码很简单,核心就三步:

    1. 创建 Fragment
    1. 获取 FragmentManager
    1. 调用事务,添加、替换
执行流程图

二、FragmentManager

FragmentManager 是一个抽象类,定义了一些和 Fragment 相关的操作和内部类/接口。

public abstract class FragmentManager { ... }

2.1、FragmentManager 中定义的方法如下:

//开启一系列对 Fragments 的操作
public abstract FragmentTransaction beginTransaction();
//FragmentTransaction.commit() 是异步执行的,如果你想立即执行,可以调用这个方法
public abstract boolean executePendingTransactions();
//根据 ID 找到从 XML 解析出来的或者事务中添加的 Fragment
//首先会找添加到 FragmentManager 中的,找不到就去回退栈里找
public abstract Fragment findFragmentById(@IdRes int id);
//跟上面的类似,不同的是使用 tag 进行查找
public abstract Fragment findFragmentByTag(String tag);
//弹出回退栈中栈顶的 Fragment,异步执行的
public abstract void popBackStack();
//立即弹出回退栈中栈顶的,直接执行哦
public abstract boolean popBackStackImmediate();

//返回栈顶符合名称的,如果传入的 name 不为空,在栈中间找到了 Fragment,那将弹出这个Fragment 上面的所有 Fragment
//有点类似启动模式的 singleTask 的感觉
//如果传入的 name 为 null,那就和 popBackStack() 一样了
//异步执行
public abstract void popBackStack(String name, int flags);
//同步版的上面
public abstract boolean popBackStackImmediate(String name, int flags);
//和使用 name 查找、弹出一样
//不同的是这里的 id 是 FragmentTransaction.commit() 返回的 id
public abstract void popBackStack(int id, int flags);
//你懂得
public abstract boolean popBackStackImmediate(int id, int flags);
//获取回退栈中的元素个数
public abstract int getBackStackEntryCount();
//根据索引获取回退栈中的某个元素
public abstract BackStackEntry getBackStackEntryAt(int index);
//添加或者移除一个监听器
public abstract void
addOnBackStackChangedListener(OnBackStackChangedListener listener);
public abstract void
removeOnBackStackChangedListener(OnBackStackChangedListener listener);
//还定义了将一个 Fragment 实例作为参数传递
public abstract void putFragment(Bundle bundle, String key, Fragment
fragment);
public abstract Fragment getFragment(Bundle bundle, String key);
//获取 manager 中所有添加进来的 Fragment
public abstract List<Fragment> getFragments();

可以看到,定义的方法有很多是异步执行的。

2.2、内部类/接口

  • BackStackEntry:Fragment 后退栈中的一个元素
  • onBackStackChangedListener:后退栈变动监听器
  • FragmentLifecycleCallbacks: FragmentManager 中的 Fragment 生命周期监听
//后退栈中的一个元素
public interface BackStackEntry {
  //栈中该元素的唯一标识
  public int getId();
  //获取 FragmentTransaction#addToBackStack(String) 设置的名称
  public String getName();
  @StringRes
  public int getBreadCrumbTitleRes();
  @StringRes
  public int getBreadCrumbShortTitleRes();
  public CharSequence getBreadCrumbTitle();
  public CharSequence getBreadCrumbShortTitle();
}

可以看到 BackStackEntry 的接口比较简单,关键信息就是 ID 和 Name

//在 Fragment 回退栈中有变化时回调
public interface OnBackStackChangedListener {
  public void onBackStackChanged();
}

//FragmentManager 中的 Fragment 生命周期监听
public abstract static class FragmentLifecycleCallbacks {
    public void onFragmentPreAttached(FragmentManager fm, Fragment f,Context context) {}
    public void onFragmentAttached(FragmentManager fm, Fragment f,Context context) {}
    public void onFragmentCreated(FragmentManager fm, Fragment f,Bundle savedInstanceState) {}
    public void onFragmentActivityCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {}
    public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {}
    public void onFragmentStarted(FragmentManager fm, Fragment f) {}
    public void onFragmentResumed(FragmentManager fm, Fragment f) {}
    public void onFragmentPaused(FragmentManager fm, Fragment f) {}
    public void onFragmentStopped(FragmentManager fm, Fragment f) {}
    public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {}
    public void onFragmentViewDestroyed(FragmentManager fm, Fragment f){}
    public void onFragmentDestroyed(FragmentManager fm, Fragment f) {}
    public void onFragmentDetached(FragmentManager fm, Fragment f) {}
 }
}

熟悉 Fragment 生命周期的同学一定觉得很面熟,这个接口就是为我们提供一个 FragmentManager 所有 Fragment 生命周期变化的回调。

可以看到, FragmentManager 是一个抽象类,它定义了对一个 Activity/Fragment 中 添加进来的Fragment 列表、Fragment 回退栈的操作、管理

三、FragmentManagerImpl

FragmentManager 定义的任务是由 FragmentManagerImpl 实现的。

final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {

    static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
    static final String TARGET_STATE_TAG = "android:target_state";
    static final String VIEW_STATE_TAG = "android:view_state";
    static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";

    private static final class FragmentLifecycleCallbacksHolder {
        final FragmentLifecycleCallbacks mCallback;
        final boolean mRecursive;

        FragmentLifecycleCallbacksHolder(FragmentLifecycleCallbacks callback, boolean recursive) {
            mCallback = callback;
            mRecursive = recursive;
        }
    }
    //fragment 的操作集合
    ArrayList<OpGenerator> mPendingActions;
    boolean mExecutingActions;

    int mNextFragmentIndex = 0;
    //保存使用过的 fragment 集合
    final ArrayList<Fragment> mAdded = new ArrayList<>();
     //存活的 fragment 集合,key 是 fragment的id
    final HashMap<String, Fragment> mActive = new HashMap<>();
    //回退栈 fragment  集合
    ArrayList<BackStackRecord> mBackStack;
    //已经创建的菜单
    ArrayList<Fragment> mCreatedMenus;
    private OnBackPressedDispatcher mOnBackPressedDispatcher;
    private final OnBackPressedCallback mOnBackPressedCallback =
            new OnBackPressedCallback(false) {
        @Override
        public void handleOnBackPressed() {
            FragmentManagerImpl.this.handleOnBackPressed();
        }
    };

    // Must be accessed while locked.
    //记录回退栈信息,用到的算法类似于SparseArray
    ArrayList<BackStackRecord> mBackStackIndices;
    //记录回退栈的索引
    ArrayList<Integer> mAvailBackStackIndices;

    ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
    private final CopyOnWriteArrayList<FragmentLifecycleCallbacksHolder>
            mLifecycleCallbacks = new CopyOnWriteArrayList<>();

    int mCurState = Fragment.INITIALIZING;
    FragmentHostCallback mHost;
    FragmentContainer mContainer;
    Fragment mParent;
    @Nullable
    Fragment mPrimaryNav;

    boolean mNeedMenuInvalidate;
    boolean mStateSaved;
    boolean mStopped;
    boolean mDestroyed;
    boolean mHavePendingDeferredStart;

    // Temporary vars for removing redundant operations in BackStackRecords:
    ArrayList<BackStackRecord> mTmpRecords;
    ArrayList<Boolean> mTmpIsPop;
    ArrayList<Fragment> mTmpAddedFragments;

    // 用于状态保存和恢复的临时变量
    Bundle mStateBundle = null;
    SparseArray<Parcelable> mStateArray = null;

    // Postponed transactions.
    ArrayList<StartEnterTransitionListener> mPostponedTransactions;

    private FragmentManagerViewModel mNonConfig;
}

四、事务

BackStackRecord (事务真正实现/回退栈)继承了 FragmentTransaction :

final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {
    static final String TAG = FragmentManagerImpl.TAG;
    //维护 FragmentManager
    final FragmentManagerImpl mManager;

    boolean mCommitted;
    int mIndex = -1;
    ...
}

4.1、FragmentTransaction

FragmentTransaction 定义了一系列对 Fragment 的操作方法:

//它会调用 add(int, Fragment, String),其中第一个参数传的是 0
public abstract FragmentTransaction add(Fragment fragment, String tag)

//它会调用 add(int, Fragment, String),其中第三个参数是 null
public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment);

//添加一个 Fragment 给 Activity 的最终实现
//第一个参数表示 Fragment 要放置的布局 id
//第二个参数表示要添加的 Fragment,【注意】一个 Fragment 只能添加一次
//第三个参数选填,可以给 Fragment 设置一个 tag,后续可以使用这个 tag 查询它
public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment, @Nullable String tag);

//调用 replace(int, Fragment, String),第三个参数传的是 null
public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment);

//替换宿主中一个已经存在的 fragment
//这一个方法等价于先调用 remove(), 再调用 add()
public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment, @Nullable String tag);

//移除一个已经存在的 fragment
//如果之前添加到宿主上,那它的布局也会被移除
public abstract FragmentTransaction remove(Fragment fragment);

//隐藏一个已存的 fragment
//其实就是将添加到宿主上的布局隐藏
public abstract FragmentTransaction hide(Fragment fragment);

//显示前面隐藏的 fragment,这只适用于之前添加到宿主上的 fragment
public abstract FragmentTransaction show(Fragment fragment);

//将指定的 fragment 将布局上解除
//当调用这个方法时,fragment 的布局已经销毁了
public abstract FragmentTransaction detach(Fragment fragment);

//当前面解除一个 fragment 的布局绑定后,调用这个方法可以重新绑定
//这将导致该 fragment 的布局重建,然后添加、展示到界面上
public abstract FragmentTransaction attach(Fragment fragment);

4.2、事务的四种提交方式

事务最终的提交方法有四种:

    1. commit()
    1. commitAllowingStateLoss()
    1. commitNow()
    1. commitNowAllowingStateLoss(

它们之间的特点及区别如下:

public abstract int commit();

commit() 在主线程中异步执行,其实也是 Handler 抛出任务,等待主线程调度执行。

注意:
commit() 需要在宿主 Activity 保存状态之前调用,否则会报错。
这是因为如果 Activity 出现异常需要恢复状态,在保存状态之后的 commit() 将会丢失,这和调用的初衷不符,所以会报错。

public abstract int commitAllowingStateLoss();

commitAllowingStateLoss() 也是异步执行,但它的不同之处在于,允许在 Activity 保存状态之后调用,也就是说它遇到状态丢失不会报错。
因此我们一般在界面状态出错是可以接受的情况下使用它。

public abstract void commitNow();

commitNow() 是同步执行的,立即提交任务。
前面提到 FragmentManager.executePendingTransactions() 也可以实现立即提交事务。但我们一般建议使用 commitNow() , 因为另外那位是一下子执行所有待执行的任务,可能会把当前所有的事务都一下子执行了,这有可能有副作用。

此外,这个方法提交的事务可能不会被添加到 FragmentManger 的后退栈,因为你这样直接提交,有可能影响其他异步执行任务在栈中的顺序。

和 commit() 一样, commitNow() 也必须在 Activity 保存状态前调用,否则会抛异常。

public abstract void commitNowAllowingStateLoss();

同步执行的 commitNowAllowingStateLoss() >

五、保存状态

FragmentActivity执行onSaveInstanceState

    static final String FRAGMENTS_TAG = "android:support:fragments";
    static final String NEXT_CANDIDATE_REQUEST_INDEX_TAG = "android:support:next_request_index";
    static final String ALLOCATED_REQUEST_INDICIES_TAG = "android:support:request_indicies";
    static final String REQUEST_FRAGMENT_WHO_TAG = "android:support:request_fragment_who";

    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        markFragmentsCreated();
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        if (mPendingFragmentActivityResults.size() > 0) {
            outState.putInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG, mNextCandidateRequestIndex);

            int[] requestCodes = new int[mPendingFragmentActivityResults.size()];
            String[] fragmentWhos = new String[mPendingFragmentActivityResults.size()];
            for (int i = 0; i < mPendingFragmentActivityResults.size(); i++) {
                requestCodes[i] = mPendingFragmentActivityResults.keyAt(i);
                fragmentWhos[i] = mPendingFragmentActivityResults.valueAt(i);
            }
            outState.putIntArray(ALLOCATED_REQUEST_INDICIES_TAG, requestCodes);
            outState.putStringArray(REQUEST_FRAGMENT_WHO_TAG, fragmentWhos);
        }
    }

执行FragmentController#saveAllState

    private final FragmentHostCallback<?> mHost;

    public Parcelable saveAllState() {
        return mHost.mFragmentManager.saveAllState();
    }

执行FragmentManagerImpl#saveAllState保存状态

    Parcelable saveAllState() {
        // Make sure all pending operations have now been executed to get
        // our state update-to-date.
        forcePostponedTransactions();
        endAnimatingAwayFragments();
        execPendingActions();
        //保存标记,标志位至 true
        mStateSaved = true;

        if (mActive.isEmpty()) {
            return null;
        }

        // First collect all active fragments.
        int size = mActive.size();
        ArrayList<FragmentState> active = new ArrayList<>(size);
        boolean haveFragments = false;
        for (Fragment f : mActive.values()) {
            if (f != null) {
                if (f.mFragmentManager != this) {
                    throwException(new IllegalStateException(
                            "Failure saving state: active " + f
                                    + " was removed from the FragmentManager"));
                }

                haveFragments = true;
                //用于保存fragment的成员变量
                FragmentState fs = new FragmentState(f);
                active.add(fs);

                if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
                    //这里面会保存view树
                    fs.mSavedFragmentState = saveFragmentBasicState(f);

                    if (f.mTargetWho != null) {
                        Fragment target = mActive.get(f.mTargetWho);
                        if (target == null) {
                            throwException(new IllegalStateException(
                                    "Failure saving state: " + f
                                            + " has target not in fragment manager: "
                                            + f.mTargetWho));
                        }
                        if (fs.mSavedFragmentState == null) {
                            fs.mSavedFragmentState = new Bundle();
                        }
                        putFragment(fs.mSavedFragmentState,
                                FragmentManagerImpl.TARGET_STATE_TAG, target);
                        if (f.mTargetRequestCode != 0) {
                            fs.mSavedFragmentState.putInt(
                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
                                    f.mTargetRequestCode);
                        }
                    }

                } else {
                    fs.mSavedFragmentState = f.mSavedFragmentState;
                }

                if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
                        + fs.mSavedFragmentState);
            }
        }

        if (!haveFragments) {
            if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
            return null;
        }

        ArrayList<String> added = null;
        BackStackState[] backStack = null;

        // Build list of currently added fragments.
        size = mAdded.size();
        if (size > 0) {
            added = new ArrayList<>(size);
            for (Fragment f : mAdded) {
                //这里开始保存fragment的唯一标识
                added.add(f.mWho);
                if (f.mFragmentManager != this) {
                    throwException(new IllegalStateException(
                            "Failure saving state: active " + f
                                    + " was removed from the FragmentManager"));
                }
                if (DEBUG) {
                    Log.v(TAG, "saveAllState: adding fragment (" + f.mWho
                            + "): " + f);
                }
            }
        }

        //保存回退栈信息
        if (mBackStack != null) {
            size = mBackStack.size();
            if (size > 0) {
                backStack = new BackStackState[size];
                for (int i = 0; i < size; i++) {
                    backStack[i] = new BackStackState(mBackStack.get(i));
                    if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
                            + ": " + mBackStack.get(i));
                }
            }
        }
        //保存FragmentManagerImpl的整体信息
        FragmentManagerState fms = new FragmentManagerState();
        fms.mActive = active;
        fms.mAdded = added;
        fms.mBackStack = backStack;
        if (mPrimaryNav != null) {
            fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
        }
        fms.mNextFragmentIndex = mNextFragmentIndex;
        return fms;
    }

六、恢复状态

FragmentActivity#onCreate中方进行恢复

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);

        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            //把之前保存的数据取回来
            mFragments.restoreSaveState(p);

            // Check if there are any pending onActivityResult calls to descendent Fragments.
            if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
                mNextCandidateRequestIndex =
                        savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
                int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
                String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
                if (requestCodes == null || fragmentWhos == null ||
                        requestCodes.length != fragmentWhos.length) {
                    Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
                } else {
                    mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
                    for (int i = 0; i < requestCodes.length; i++) {
                        mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
                    }
                }
            }
        }

        if (mPendingFragmentActivityResults == null) {
            mPendingFragmentActivityResults = new SparseArrayCompat<>();
            mNextCandidateRequestIndex = 0;
        }

        super.onCreate(savedInstanceState);
        //更改状态
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        //分发 炽热create 事件
        mFragments.dispatchCreate();
    }

执行FragmentController#restoreSaveState

    public void restoreSaveState(@Nullable Parcelable state) {
        if (!(mHost instanceof ViewModelStoreOwner)) {
            throw new IllegalStateException("Your FragmentHostCallback must implement "
                    + "ViewModelStoreOwner to call restoreSaveState(). Call restoreAllState() "
                    + " if you're still using retainNestedNonConfig().");
        }
        mHost.mFragmentManager.restoreSaveState(state);
    }

执行FragmentManagerImpl#restoreSaveState恢复数据

    void restoreSaveState(Parcelable state) {
        // If there is no saved state at all, then there's nothing else to do
        if (state == null) return;
        FragmentManagerState fms = (FragmentManagerState)state;
        if (fms.mActive == null) return;

        // First re-attach any non-config instances we are retaining back
        // to their saved state, so we don't try to instantiate them again.
        for (Fragment f : mNonConfig.getRetainedFragments()) {
            if (DEBUG) Log.v(TAG, "restoreSaveState: re-attaching retained " + f);
            FragmentState fs = null;
            for (FragmentState fragmentState : fms.mActive) {
                if (fragmentState.mWho.equals(f.mWho)) {
                    fs = fragmentState;
                    break;
                }
            }
            if (fs == null) {
                if (DEBUG) {
                    Log.v(TAG, "Discarding retained Fragment " + f
                            + " that was not found in the set of active Fragments " + fms.mActive);
                }
                // 重新执行fragment生命周期.
                moveToState(f, Fragment.CREATED, 0, 0, false);
                f.mRemoving = true;
                moveToState(f, Fragment.INITIALIZING, 0, 0, false);
                continue;
            }
            fs.mInstance = f;
            f.mSavedViewState = null;
            f.mBackStackNesting = 0;
            f.mInLayout = false;
            f.mAdded = false;
            f.mTargetWho = f.mTarget != null ? f.mTarget.mWho : null;
            f.mTarget = null;
            if (fs.mSavedFragmentState != null) {
                fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
                f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
                        FragmentManagerImpl.VIEW_STATE_TAG);
                f.mSavedFragmentState = fs.mSavedFragmentState;
            }
        }

        // Build the full list of active fragments, instantiating them from
        // their saved state.
        mActive.clear();
        for (FragmentState fs : fms.mActive) {
            if (fs != null) {
                Fragment f = fs.instantiate(mHost.getContext().getClassLoader(),
                        getFragmentFactory());
                f.mFragmentManager = this;
                if (DEBUG) Log.v(TAG, "restoreSaveState: active (" + f.mWho + "): " + f);
                mActive.put(f.mWho, f);
                // Now that the fragment is instantiated (or came from being
                // retained above), clear mInstance in case we end up re-restoring
                // from this FragmentState again.
                fs.mInstance = null;
            }
        }

        // Build the list of currently added fragments.
        mAdded.clear();
        if (fms.mAdded != null) {
            for (String who : fms.mAdded) {
                Fragment f = mActive.get(who);
                if (f == null) {
                    throwException(new IllegalStateException(
                            "No instantiated fragment for (" + who + ")"));
                }
                f.mAdded = true;
                if (DEBUG) Log.v(TAG, "restoreSaveState: added (" + who + "): " + f);
                if (mAdded.contains(f)) {
                    throw new IllegalStateException("Already added " + f);
                }
                synchronized (mAdded) {
                    mAdded.add(f);
                }
            }
        }

        // Build the back stack.
        if (fms.mBackStack != null) {
            mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
            for (int i=0; i<fms.mBackStack.length; i++) {
                BackStackRecord bse = fms.mBackStack[i].instantiate(this);
                if (DEBUG) {
                    Log.v(TAG, "restoreAllState: back stack #" + i
                            + " (index " + bse.mIndex + "): " + bse);
                    LogWriter logw = new LogWriter(TAG);
                    PrintWriter pw = new PrintWriter(logw);
                    bse.dump("  ", pw, false);
                    pw.close();
                }
                mBackStack.add(bse);
                if (bse.mIndex >= 0) {
                    setBackStackIndex(bse.mIndex, bse);
                }
            }
        } else {
            mBackStack = null;
        }

        if (fms.mPrimaryNavActiveWho != null) {
            mPrimaryNav = mActive.get(fms.mPrimaryNavActiveWho);
            dispatchParentPrimaryNavigationFragmentChanged(mPrimaryNav);
        }
        this.mNextFragmentIndex = fms.mNextFragmentIndex;
    }

七、添加一个 Fragment 到布局 add() 的实现

执行FragmentTransaction#add

    @NonNull
    public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)  {
        doAddOp(0, fragment, tag, OP_ADD);
        return this;
    }
    @NonNull
    public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
        doAddOp(containerViewId, fragment, null, OP_ADD);
        return this;
    }

    @NonNull
    public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
            @Nullable String tag) {
        doAddOp(containerViewId, fragment, tag, OP_ADD);
        return this;
    }

执行FragmentTransaction#doAddOp

    ArrayList<Op> mOps = new ArrayList<>();

    void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
        final Class<?> fragmentClass = fragment.getClass();
        final int modifiers = fragmentClass.getModifiers();
        if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
                || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
            throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
                    + " must be a public static class to be  properly recreated from"
                    + " instance state.");
        }

        if (tag != null) {
            if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
                throw new IllegalStateException("Can't change tag of fragment "
                        + fragment + ": was " + fragment.mTag
                        + " now " + tag);
            }
            //设置 tag
            fragment.mTag = tag;
        }

        if (containerViewId != 0) {
            if (containerViewId == View.NO_ID) {
                throw new IllegalArgumentException("Can't add fragment "
                        + fragment + " with tag " + tag + " to container view with no id");
            }
            if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
                throw new IllegalStateException("Can't change container ID of fragment "
                        + fragment + ": was " + fragment.mFragmentId
                        + " now " + containerViewId);
            }
            //设置宿主 ID 为布局 ID
            fragment.mContainerId = fragment.mFragmentId = containerViewId;
        }
        //把Fragment和对应的事务封装到Op类中
        addOp(new Op(opcmd, fragment));
    }

    void addOp(Op op) {
        //把op添加到集合中
        mOps.add(op);
        op.mEnterAnim = mEnterAnim;
        op.mExitAnim = mExitAnim;
        op.mPopEnterAnim = mPopEnterAnim;
        op.mPopExitAnim = mPopExitAnim;
    }

接下来看new Op(opcmd, fragment)

    static final class Op {
        int mCmd;
        Fragment mFragment;
        int mEnterAnim;
        int mExitAnim;
        int mPopEnterAnim;
        int mPopExitAnim;
        Lifecycle.State mOldMaxState;
        Lifecycle.State mCurrentMaxState;

        Op() {
        }

        Op(int cmd, Fragment fragment) {
            this.mCmd = cmd;   //状态
            this.mFragment = fragment;
            this.mOldMaxState = Lifecycle.State.RESUMED;
            this.mCurrentMaxState = Lifecycle.State.RESUMED;
        }

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

推荐阅读更多精彩内容