FragmentManager  详解

FragmentManager  详解

FragmentManager 是用来管理Fragment 负责 添加 移除 显示 隐藏,FragmentManager 是抽象类她的具体实现类是FragmentManagerImpl 是FragmentManager的内部类

FragmentActivity 中调用 getSupportFragmentManager() 来进行fragment 管理,这里我们先看下 FragmentActivity源码如下:

在FragmentActivity 中调用getSupportFragmentManager() 

public class FragmentActivity extends BaseFragmentActivityJB {

//创建 FragmentController 并 new HostCallbacks()父类就是FragmentHostCallback()
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
//创建createController 并需要传 FragmentHostCallback对象
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
    return new FragmentController(callbacks);
}
// new HostCallbacks() 并通过 super(FragmentActivity.this /*fragmentActivity*/);
//将当前FragmentActivity.this 传给FragmentHostCallback
class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
   public HostCallbacks() {
      super(FragmentActivity.this /*fragmentActivity*/);
   }
}

//通过 super(FragmentActivity.this /*fragmentActivity*/)
FragmentHostCallback(FragmentActivity activity) {
    this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
}
//mActivity 赋值
//mContext activity强转Context
//mHandler 获取activity.mHandler 
FragmentHostCallback(Activity activity, Context context, Handler handler,
        int windowAnimations) {
    mActivity = activity;
    mContext = context;
    mHandler = handler;
    mWindowAnimations = windowAnimations;
}
//mHost 是 FragmentHostCallback 调用 FragmentHostCallback.getFragmentManagerImpl()
public FragmentManager getSupportFragmentManager() {
    return mHost.getFragmentManagerImpl();
}

这里我们看到FragmentActivity 启动完成后会创建FragmentController.createController(new HostCallbacks()) 并需要传HostCallbacks()是继承FragmentHostCallback()通过 super(FragmentActivity.this /*fragmentActivity*/) 将FragmentActivity.this传给FragmentHostCallback() 并执行四个参数的构造方法 分别给mActivity 赋值,将mActivity强转 mContext并赋值mContext,获取mActivity的mHandler并赋值给mHandler,第四个参数是0

这里还看到 getSupportFragmentManager() 实际上就是通过FragmentHostCallback 的 getFragmentManagerImpl方法 getFragmentManagerImpl就是创建一个FragmentManager类的具体实现类FragmentManagerImpl代码如下:

public abstract class FragmentHostCallback<E> extends FragmentContainer {
 
    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
    
    FragmentManagerImpl getFragmentManagerImpl() {
       return mFragmentManager;
    }
}

这里创建FragmentManagerImpl ,就是说 getSupportFragmentManager就是创建一个FragmentManagerImpl,第二步是获取一个beginTransaction ,这里介绍下FragmentTransaction,FragmentTransaction也是一个抽象类他的具体实现类是BackStackRecord代码如下:

@Override
public FragmentTransaction beginTransaction() {
  //创建FragmentTransaction 具体实现类是BackStackRecord ,并将FragmentManagerImpl传过去
    return new BackStackRecord(this);
}
public BackStackRecord(FragmentManagerImpl manager) {
    mManager = manager;
}

getSupportFragmentManager().beginTransaction().replace(id,framgnet).commit()

BackStackRecord 是FragmentTransaction的子类所以你在FragmentTransaction.add 或者replace都是调到BackStackRecord中方法,接下我们看下replace方法都做了什么:

public FragmentTransaction replace(int containerViewId, Fragment fragment) {
    return replace(containerViewId, fragment, null);
}
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
    if (containerViewId == 0) {
        throw new IllegalArgumentException("Must use non-zero containerViewId");
    }

    doAddOp(containerViewId, fragment, tag, OP_REPLACE);
    return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
   //这里将mFragmentManager 赋值成最新mManager
    fragment.mFragmentManager = mManager;

    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);
        }
        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);
        }
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }
  // 创建 Op对象
    Op op = new Op();
    op.cmd = opcmd;
    op.fragment = fragment;
    addOp(op);
}
//这是设置fragment 加载样式
void addOp(Op op) {
    if (mHead == null) {
        mHead = mTail = op;
    } else {
        op.prev = mTail;
        mTail.next = op;
        mTail = op;
    }
    op.enterAnim = mEnterAnim;
    op.exitAnim = mExitAnim;
    op.popEnterAnim = mPopEnterAnim;
    op.popExitAnim = mPopExitAnim;
    mNumOp++;
}

其实replace并灭有实际上添加显示,只将mFragmentManager 该变成最新FragmentManager 并配置fragment 加载样式,最后我们在看下commit方法如下:

public int commit() {
    return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
    //mCommitted 防止重复提交两次commit
    if (mCommitted) {
        throw new IllegalStateException("commit already called");
    }
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

mManager FragmentManagerImpl 是 执行 mManager.enqueueAction(this, allowStateLoss);方法

public void enqueueAction(Runnable action, boolean allowStateLoss) {
    synchronized (this) {
        
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<Runnable>();
        }
        mPendingActions.add(action);
        if (mPendingActions.size() == 1) {
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
        }
    }
}

mHost 获取Handler() 执行post方法

Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};

执行Runnable 的execPendingActions方法

/**
 * Only call from main thread!
 */
public boolean execPendingActions() {


    doPendingDeferredStart();

    return didSomething;
}
void doPendingDeferredStart() {
        if (!loadersRunning) {
            mHavePendingDeferredStart = false;
            startPendingDeferredFragments();
        }
}
void startPendingDeferredFragments() {
    if (mActive == null) return;

    for (int i=0; i<mActive.size(); i++) {
        Fragment f = mActive.get(i);
        if (f != null) {
            performPendingDeferredStart(f);
        }
    }
}
public void performPendingDeferredStart(Fragment f) {
    if (f.mDeferStart) {
        if (mExecutingActions) {
            // Wait until we're done executing our pending transactions
            mHavePendingDeferredStart = true;
            return;
        }
        f.mDeferStart = false;
        moveToState(f, mCurState, 0, 0, false);
    }
}
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    if (DEBUG && false) Log.v(TAG, "moveToState: " + f
        + " oldState=" + f.mState + " newState=" + newState
        + " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));

    // Fragments that are not currently added will sit in the onCreate() state.
    if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
        newState = Fragment.CREATED;
    }
    if (f.mRemoving && newState > f.mState) {
        // While removing a fragment, we can't change it to a higher state.
        newState = f.mState;
    }
    // Defer start if requested; don't allow it to move to STARTED or higher
    // if it's not already started.
    if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
        newState = Fragment.STOPPED;
    }
    if (f.mState < newState) {
        // For fragments that are created from a layout, when restoring from
        // state we don't want to allow them to be created until they are
        // being reloaded from the layout.
        if (f.mFromLayout && !f.mInLayout) {
            return;
        }
        if (f.mAnimatingAway != null) {
            // The fragment is currently being animated...  but!  Now we
            // want to move our state back up.  Give up on waiting for the
            // animation, move to whatever the final state should be once
            // the animation is done, and then we can proceed from there.
            f.mAnimatingAway = null;
            moveToState(f, f.mStateAfterAnimating, 0, 0, true);
        }
        switch (f.mState) {
            case Fragment.INITIALIZING:
                if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
                if (f.mSavedFragmentState != null) {
                    f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
                            FragmentManagerImpl.VIEW_STATE_TAG);
                    f.mTarget = getFragment(f.mSavedFragmentState,
                            FragmentManagerImpl.TARGET_STATE_TAG);
                    if (f.mTarget != null) {
                        f.mTargetRequestCode = f.mSavedFragmentState.getInt(
                                FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
                    }
                    f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
                            FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
                    if (!f.mUserVisibleHint) {
                        f.mDeferStart = true;
                        if (newState > Fragment.STOPPED) {
                            newState = Fragment.STOPPED;
                        }
                    }
                }
                f.mHost = mHost;
                f.mParentFragment = mParent;
                f.mFragmentManager = mParent != null
                        ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
                f.mCalled = false;
                f.onAttach(mHost.getContext());
                if (!f.mCalled) {
                    throw new SuperNotCalledException("Fragment " + f
                            + " did not call through to super.onAttach()");
                }
                if (f.mParentFragment == null) {
                    mHost.onAttachFragment(f);
                } else {
                    f.mParentFragment.onAttachFragment(f);
                }

                if (!f.mRetaining) {
                    f.performCreate(f.mSavedFragmentState);
                } else {
                    f.restoreChildFragmentState(f.mSavedFragmentState, true);
                    f.mState = Fragment.CREATED;
                }
                f.mRetaining = false;
                if (f.mFromLayout) {
                    // For fragments that are part of the content view
                    // layout, we need to instantiate the view immediately
                    // and the inflater will take care of adding it.
                    f.mView = f.performCreateView(f.getLayoutInflater(
                            f.mSavedFragmentState), null, f.mSavedFragmentState);
                    if (f.mView != null) {
                        f.mView.setSaveFromParentEnabled(false);
                        if (f.mHidden) f.mView.setVisibility(View.GONE);
                        f.onViewCreated(f.mView, f.mSavedFragmentState);
                    }
                }
            case Fragment.CREATED:
                if (newState > Fragment.CREATED) {
                    if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                    if (!f.mFromLayout) {
                        ViewGroup container = null;
                        if (f.mContainerId != 0) {
                            if (f.mContainerId == View.NO_ID) {
                                throwException(new IllegalArgumentException(
                                        "Cannot create fragment "
                                                + f
                                                + " for a container view with no id"));
                            }
                            container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                            if (container == null && !f.mRestored) {
                                String resName;
                                try {
                                    resName = f.getResources().getResourceName(f.mContainerId);
                                } catch (NotFoundException e) {
                                    resName = "unknown";
                                }
                                throwException(new IllegalArgumentException(
                                        "No view found for id 0x"
                                        + Integer.toHexString(f.mContainerId) + " ("
                                        + resName
                                        + ") for fragment " + f));
                            }
                        }
                        f.mContainer = container;
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), container, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mView.setSaveFromParentEnabled(false);
                            if (container != null) {
                                Animator anim = loadAnimator(f, transit, true,
                                        transitionStyle);
                                if (anim != null) {
                                    anim.setTarget(f.mView);
                                    setHWLayerAnimListenerIfAlpha(f.mView, anim);
                                    anim.start();
                                }
                                container.addView(f.mView);
                            }
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        }
                    }

                    f.performActivityCreated(f.mSavedFragmentState);
                    if (f.mView != null) {
                        f.restoreViewState(f.mSavedFragmentState);
                    }
                    f.mSavedFragmentState = null;
                }
            case Fragment.ACTIVITY_CREATED:
                if (newState > Fragment.ACTIVITY_CREATED) {
                    f.mState = Fragment.STOPPED;
                }
            case Fragment.STOPPED:
                if (newState > Fragment.STOPPED) {
                    if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                    f.performStart();
                }
            case Fragment.STARTED:
                if (newState > Fragment.STARTED) {
                    if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                    f.performResume();
                    // Get rid of this in case we saved it and never needed it.
                    f.mSavedFragmentState = null;
                    f.mSavedViewState = null;
                }
        }
    } else if (f.mState > newState) {
        switch (f.mState) {
            case Fragment.RESUMED:
                if (newState < Fragment.RESUMED) {
                    if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                    f.performPause();
                }
            case Fragment.STARTED:
                if (newState < Fragment.STARTED) {
                    if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                    f.performStop();
                }
            case Fragment.STOPPED:
            case Fragment.ACTIVITY_CREATED:
                if (newState < Fragment.ACTIVITY_CREATED) {
                    if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                    if (f.mView != null) {
                        // Need to save the current view state if not
                        // done already.
                        if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                            saveFragmentViewState(f);
                        }
                    }
                    f.performDestroyView();
                    if (f.mView != null && f.mContainer != null) {
                        Animator anim = null;
                        if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
                            anim = loadAnimator(f, transit, false,
                                    transitionStyle);
                        }
                        if (anim != null) {
                            final ViewGroup container = f.mContainer;
                            final View view = f.mView;
                            final Fragment fragment = f;
                            container.startViewTransition(view);
                            f.mAnimatingAway = anim;
                            f.mStateAfterAnimating = newState;
                            anim.addListener(new AnimatorListenerAdapter() {
                                @Override
                                public void onAnimationEnd(Animator anim) {
                                    container.endViewTransition(view);
                                    if (fragment.mAnimatingAway != null) {
                                        fragment.mAnimatingAway = null;
                                        moveToState(fragment, fragment.mStateAfterAnimating,
                                                0, 0, false);
                                    }
                                }
                            });
                            anim.setTarget(f.mView);
                            setHWLayerAnimListenerIfAlpha(f.mView, anim);
                            anim.start();

                        }
                        f.mContainer.removeView(f.mView);
                    }
                    f.mContainer = null;
                    f.mView = null;
                }
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                    if (mDestroyed) {
                        if (f.mAnimatingAway != null) {
                            // The fragment's containing activity is
                            // being destroyed, but this fragment is
                            // currently animating away.  Stop the
                            // animation right now -- it is not needed,
                            // and we can't wait any more on destroying
                            // the fragment.
                            Animator anim = f.mAnimatingAway;
                            f.mAnimatingAway = null;
                            anim.cancel();
                        }
                    }
                    if (f.mAnimatingAway != null) {
                        // We are waiting for the fragment's view to finish
                        // animating away.  Just make a note of the state
                        // the fragment now should move to once the animation
                        // is done.
                        f.mStateAfterAnimating = newState;
                        newState = Fragment.CREATED;
                    } else {
                        if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                        if (!f.mRetaining) {
                            f.performDestroy();
                        } else {
                            f.mState = Fragment.INITIALIZING;
                        }

                        f.performDetach();
                        if (!keepActive) {
                            if (!f.mRetaining) {
                                makeInactive(f);
                            } else {
                                f.mHost = null;
                                f.mParentFragment = null;
                                f.mFragmentManager = null;
                            }
                        }
                    }
                }
        }
    }
    
    if (f.mState != newState) {
        Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
                + "expected state " + newState + " found " + f.mState);
        f.mState = newState;
    }
}

这里重点讲下 commit 和 commitAllowingStateLoss 区别

 

public int commit() {
    return commitInternal(false);
}

public int commitAllowingStateLoss() {
    return commitInternal(true);
}

它两其实是调用的是通一个方法只是参数不同

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) {
        throw new IllegalStateException("commit already called");
    }
   
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}
public int allocBackStackIndex(BackStackRecord bse) {
    synchronized (this) {
        if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
            if (mBackStackIndices == null) {
                mBackStackIndices = new ArrayList<BackStackRecord>();
            }
            int index = mBackStackIndices.size();
            if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
            mBackStackIndices.add(bse);
            return index;

        } else {
            int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
            if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
            mBackStackIndices.set(index, bse);
            return index;
        }
    }
}

allowStateLoss 是false  commit 默认是-1 . allowStateLoss为true 而 commitAllowingStateLoss调用 FragmentManagerImpl 的allocBackStackIndex 方法  创建 ArrayList 将BackStackRecord存储在ArrayList 然后在返回他的size 

//加入Back返回栈
fragmentTransaction.addToBackStack(null);

//android.support.v4.app.BackStackRecord
//提交 
public int commit() {
    return commitInternal(false);
}

int commitInternal(boolean allowStateLoss) {
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    //mManager 是 FragmentManagerImpl 执行enqueueAction
     mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

//android.support.v4.app.FragmentManagerImpl

public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        checkStateLoss();
    }
    synchronized (this) {
        if (mDestroyed || mHost == null) {
        
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<>();
        }
        mPendingActions.add(action);
        scheduleCommit();
    }
}
private void scheduleCommit() {
    synchronized (this) {
        boolean postponeReady =
                mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            mHost.getHandler().removeCallbacks(mExecCommit);\
            //mExecCommit
            mHost.getHandler().post(mExecCommit);
        }
    }
}
Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
       //execPendingActions
        execPendingActions();
    }
};
public boolean execPendingActions() {
    ensureExecReady(true);

boolean didSomething = false;
//generateOpsForPendingActions
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
    mExecutingActions = true;
    try {
        //创建
        removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
    } finally {
        cleanupExec();
    }
    didSomething = true;
   }
    return didSomething;
}
private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop) {
    if (records == null || records.isEmpty()) {
        return;
    }

    if (isRecordPop == null || records.size() != isRecordPop.size()) {
        throw new IllegalStateException("Internal error with the back stack records");
    }

    // Force start of any postponed transactions that interact with scheduled transactions:
    executePostponedTransaction(records, isRecordPop);

    final int numRecords = records.size();
    int startIndex = 0;
    for (int recordNum = 0; recordNum < numRecords; recordNum++) {
        final boolean canReorder = records.get(recordNum).mReorderingAllowed;
        if (!canReorder) {
            // execute all previous transactions
            if (startIndex != recordNum) {
                executeOpsTogether(records, isRecordPop, startIndex, recordNum);
            }
            // execute all pop operations that don't allow reordering together or
            // one add operation
            int reorderingEnd = recordNum + 1;
            if (isRecordPop.get(recordNum)) {
                while (reorderingEnd < numRecords
                        && isRecordPop.get(reorderingEnd)
                        && !records.get(reorderingEnd).mReorderingAllowed) {
                    reorderingEnd++;
                }
            }
            executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
            startIndex = reorderingEnd;
            recordNum = reorderingEnd - 1;
        }
    }
    if (startIndex != numRecords) {
     // executeOpsTogether
        executeOpsTogether(records, isRecordPop, startIndex, numRecords);
    }
}
private void executeOpsTogether(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
    boolean addToBackStack = false;
    if (mTmpAddedFragments == null) {
        mTmpAddedFragments = new ArrayList<>();
    } else {
        mTmpAddedFragments.clear();
    }
    mTmpAddedFragments.addAll(mAdded);
    Fragment oldPrimaryNav = getPrimaryNavigationFragment();
    for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
        final BackStackRecord record = records.get(recordNum);
        final boolean isPop = isRecordPop.get(recordNum);
        if (!isPop) {
            oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
        } else {
            oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
        }
        addToBackStack = addToBackStack || record.mAddToBackStack;
    }
    mTmpAddedFragments.clear();

    if (!allowReordering) {
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
                false);
    }
    // executeOps
    executeOps(records, isRecordPop, startIndex, endIndex);

    int postponeIndex = endIndex;
    if (allowReordering) {
        ArraySet<Fragment> addedFragments = new ArraySet<>();
        addAddedFragments(addedFragments);
        postponeIndex = postponePostponableTransactions(records, isRecordPop,
                startIndex, endIndex, addedFragments);
        makeRemovedFragmentsInvisible(addedFragments);
    }

    if (postponeIndex != startIndex && allowReordering) {
        // need to run something now
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex,
                postponeIndex, true);
        moveToState(mCurState, true);
    }

    for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
        final BackStackRecord record = records.get(recordNum);
        final boolean isPop = isRecordPop.get(recordNum);
        if (isPop && record.mIndex >= 0) {
            freeBackStackIndex(record.mIndex);
            record.mIndex = -1;
        }
        record.runOnCommitRunnables();
    }
    if (addToBackStack) {
        reportBackStackChanged();
    }
}
private static void executeOps(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    for (int i = startIndex; i < endIndex; i++) {
        final BackStackRecord record = records.get(i);
        final boolean isPop = isRecordPop.get(i);
        if (isPop) {
            record.bumpBackStackNesting(-1);
            // Only execute the add operations at the end of
            // all transactions.
            boolean moveToState = i == (endIndex - 1);
            // executePopOps
            record.executePopOps(moveToState);
        } else {
            record.bumpBackStackNesting(1);
            record.executeOps();
        }
    }
}
void executePopOps(boolean moveToState) {
    for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
        final Op op = mOps.get(opNum);
        Fragment f = op.fragment;
        if (f != null) {
            f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition),
                    mTransitionStyle);
        }
        switch (op.cmd) {
            case OP_ADD:
                f.setNextAnim(op.popExitAnim);
                mManager.removeFragment(f);
                break;
            case OP_REMOVE:
                f.setNextAnim(op.popEnterAnim);
                mManager.addFragment(f, false);
                break;
            case OP_HIDE:
                f.setNextAnim(op.popEnterAnim);
                mManager.showFragment(f);
                break;
            case OP_SHOW:
                f.setNextAnim(op.popExitAnim);
                mManager.hideFragment(f);
                break;
            case OP_DETACH:
                f.setNextAnim(op.popEnterAnim);
                mManager.attachFragment(f);
                break;
            case OP_ATTACH:
                f.setNextAnim(op.popExitAnim);
                mManager.detachFragment(f);
                break;
            case OP_SET_PRIMARY_NAV:
                mManager.setPrimaryNavigationFragment(null);
                break;
            case OP_UNSET_PRIMARY_NAV:
                mManager.setPrimaryNavigationFragment(f);
                break;
            default:
                throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
        }
        if (!mReorderingAllowed && op.cmd != OP_REMOVE && f != null) {
            mManager.moveFragmentToExpectedState(f);
        }
    }
    if (!mReorderingAllowed && moveToState) {
        mManager.moveToState(mManager.mCurState, true);
    }
}
public void addFragment(Fragment fragment, boolean moveToStateNow) {
    if (DEBUG) Log.v(TAG, "add: " + fragment);
    makeActive(fragment);
    if (!fragment.mDetached) {
        if (mAdded.contains(fragment)) {
            throw new IllegalStateException("Fragment already added: " + fragment);
        }
        synchronized (mAdded) {
            mAdded.add(fragment);
        }
        fragment.mAdded = true;
        fragment.mRemoving = false;
        if (fragment.mView == null) {
            fragment.mHiddenChanged = false;
        }
        if (fragment.mHasMenu && fragment.mMenuVisible) {
            mNeedMenuInvalidate = true;
        }
        if (moveToStateNow) {
            moveToState(fragment);
        }
    }
}
void makeActive(Fragment f) {
    if (f.mIndex >= 0) {
        return;
    }

    f.setIndex(mNextFragmentIndex++, mParent);
    if (mActive == null) {
        mActive = new SparseArray<>();
    }
    mActive.put(f.mIndex, f);
    if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
}
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isPop) {
    boolean didSomething = false;
    synchronized (this) {
        if (mPendingActions == null || mPendingActions.size() == 0) {
            return false;
        }

        final int numActions = mPendingActions.size();
        for (int i = 0; i < numActions; i++) {      
            //执行 generateOps
            didSomething |= mPendingActions.get(i).generateOps(records, isPop);
        }
        mPendingActions.clear();
        mHost.getHandler().removeCallbacks(mExecCommit);
    }
    return didSomething;
}
 /android/support/v4/app/BackStackRecord.java
@Override
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
    if (FragmentManagerImpl.DEBUG) {
        Log.v(TAG, "Run: " + this);
    }

    records.add(this);
    isRecordPop.add(false);
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
    return true;
}
// addBackStackState
void addBackStackState(BackStackRecord state) {
    if (mBackStack == null) {
        mBackStack = new ArrayList<BackStackRecord>();
    }
    mBackStack.add(state);
}
添加到 mBackStack中

getSupportFragmentManager().popBackStack() 

@Override
public void popBackStack() {
    enqueueAction(new PopBackStackState(null, -1, 0), false);
}
private class PopBackStackState implements OpGenerator {
    final String mName;
    final int mId;
    final int mFlags;

    PopBackStackState(String name, int id, int flags) {
        mName = name;
        mId = id;
        mFlags = flags;
    }

    @Override
    public boolean generateOps(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop) {
        if (mPrimaryNav != null // We have a primary nav fragment
                && mId < 0 // No valid id (since they're local)
                && mName == null) { // no name to pop to (since they're local)
            final FragmentManager childManager = mPrimaryNav.peekChildFragmentManager();
            if (childManager != null && childManager.popBackStackImmediate()) {
                // We didn't add any operations for this FragmentManager even though
                // a child did do work.
                return false;
            }
        }
        return popBackStackState(records, isRecordPop, mName, mId, mFlags);
    }
}
@SuppressWarnings("unused")
boolean popBackStackState(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,
        String name, int id, int flags) {
    if (mBackStack == null) {
        return false;
    }
    if (name == null && id < 0 && (flags & POP_BACK_STACK_INCLUSIVE) == 0) {
        int last = mBackStack.size() - 1;
        if (last < 0) {
            return false;
        }
        // mBackStack.remove(last)
        records.add(mBackStack.remove(last));
        isRecordPop.add(true);
    } else {
        int index = -1;
        if (name != null || id >= 0) {
            // If a name or ID is specified, look for that place in
            // the stack.
            index = mBackStack.size()-1;
            while (index >= 0) {
                BackStackRecord bss = mBackStack.get(index);
                if (name != null && name.equals(bss.getName())) {
                    break;
                }
                if (id >= 0 && id == bss.mIndex) {
                    break;
                }
                index--;
            }
            if (index < 0) {
                return false;
            }
            if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
                index--;
                // Consume all following entries that match.
                while (index >= 0) {
                    BackStackRecord bss = mBackStack.get(index);
                    if ((name != null && name.equals(bss.getName()))
                            || (id >= 0 && id == bss.mIndex)) {
                        index--;
                        continue;
                    }
                    break;
                }
            }
        }
        if (index == mBackStack.size()-1) {
            return false;
        }
        for (int i = mBackStack.size() - 1; i > index; i--) {
            records.add(mBackStack.remove(i));
            isRecordPop.add(true);
        }
    }
    return true;
}

 


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值