[フラグメントの再検討]ソースコードからの追加と置換の違いをpopBackStackで確認してください

全体的なプロセス

前回の記事では、フラグメントのライフサイクルプロセスをアクティビティとフラグメント自体の観点から分析しました。興味のあるパートナーは、ソースコードの観点からフラグメントのライフサイクルプロセスを分析できます。これは、追加のフローチャートです。より直感的で、追加と置換のステップが異なることについても説明します。

image.png

追加および置換

ソースコードでの追加と置換の主な違いは、

  1. addとreplaceの元のop.mCmd値が異なり、1つはOP_ADDで、もう1つはOP_REPLACEである必要があります。
  2. record.expandOpsメソッドのreplaceは、OP_REPLACEをOP_REMOVEとOP_ADDに分割し、fragmentStateManager.moveToExpectedState()をループで実行します。違いはここにあります。replaceには、前のフラグメントを削除する追加の削除操作があります。削除されたフラグメントはonDestroyViewまたはonDetachに移動して、トランザクションがリターンスタックに追加されているかどうかを確認します。詳細については、3番目のポイントを参照してください。
  3. ComputeExpectedStateメソッドによって取得される期待されるライフサイクルは異なります
// fragmentStateManager
int computeExpectedState() {
    //mFragmentManagerState的值来源于创建fragmentStateManager的时候,把fragmentManager的生命周期赋值给它
    int maxState = mFragmentManagerState;

    //这个是和fragmentTransaction.setMaxLifecycle配合使用的,这里没用到,默认是RESUMED
    switch (mFragment.mMaxState) {
        case RESUMED:
            // maxState can't go any higher than RESUMED, so there's nothing to do here
            break;
        case STARTED:
            maxState = Math.min(maxState, Fragment.STARTED);
            break;
        case CREATED:
            maxState = Math.min(maxState, Fragment.CREATED);
            break;
        case INITIALIZED:
            maxState = Math.min(maxState, Fragment.ATTACHED);
            break;
        default:
            maxState = Math.min(maxState, Fragment.INITIALIZING);
    }

    //这里貌似是判断是否在xml中引入的fragment
    if (mFragment.mFromLayout) {
        if (mFragment.mInLayout) {
            // Move them immediately to VIEW_CREATED when they are
            // actually added to the layout (mInLayout).
            maxState = Math.max(mFragmentManagerState, Fragment.VIEW_CREATED);
            // But don't move to higher than VIEW_CREATED until the view is added to its parent
            // and the LayoutInflater call has returned
            if (mFragment.mView != null && mFragment.mView.getParent() == null) {
                maxState = Math.min(maxState, Fragment.VIEW_CREATED);
            }
        } else {
            if (mFragmentManagerState < Fragment.ACTIVITY_CREATED) {
                // But while they are not in the layout, don't allow their
                // state to progress upward until the FragmentManager state
                // is at least ACTIVITY_CREATED. This ensures they get the onInflate()
                // callback before being attached or created.
                maxState = Math.min(maxState, mFragment.mState);
            } else {
                // Once the FragmentManager state is at least ACTIVITY_CREATED
                // their state can progress up to CREATED as we assume that
                // they are not ever going to be in layout
                maxState = Math.min(maxState, Fragment.CREATED);
            }
        }
    }
    //如果是add提交事务的话就走不进该判断,而replace由于被拆分成remove和add
    //remove操作在executeOps方法removeFragment的时候就置为false了
    //因此此时add操作:maxState==RESUMED,remove操作:masState==CREATED
    if (!mFragment.mAdded) {
        maxState = Math.min(maxState, Fragment.CREATED);
    }
    if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.ADDING) {
        // Fragments awaiting their enter effects cannot proceed beyond that state
        maxState = Math.min(maxState, Fragment.AWAITING_ENTER_EFFECTS);
    } else if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.REMOVING) {
        // Fragments that are in the process of being removed shouldn't go below that state
        maxState = Math.max(maxState, Fragment.AWAITING_EXIT_EFFECTS);
    } 
    //这里也是同样的道理executeOps方法removeFragment的时候mRemoving会被置为true
    else if (mFragment.mRemoving) {
        //被replace的fragment是否加入了返回栈,加入了maxState==CREATED,否则为INITIALIZING
        if (mFragment.isInBackStack()) {
            // Fragments on the back stack shouldn't go higher than CREATED
            maxState = Math.min(maxState, Fragment.CREATED);
        } else {
            // While removing a fragment, we always move to INITIALIZING
            maxState = Math.min(maxState, Fragment.INITIALIZING);
        }
    }
    return maxState;
}

//moveToExpectedState方法
//通过上面可以知道remove操作得到的期望的生命周期肯定小于当前的生命周期状态,这个时候和add就是完全想反的操作了
//以下代码解释了为什么加入返回栈的只会走到onDestroyView,而未加入的会走detach
case Fragment.CREATED:
    destroyFragmentView();
    mFragment.mState = Fragment.CREATED;
    break;
case Fragment.ATTACHED:
    destroy();
    break;
case Fragment.INITIALIZING:
    detach();
    break;

フラグメントリターンスタック

addToBackStackの機能

public FragmentTransaction addToBackStack(@Nullable String name) {
    if (!mAllowAddToBackStack) {
        throw new IllegalStateException(
                "This FragmentTransaction is not allowed to be added to the back stack.");
    }
    //这里呼应了BackStackRecord的generateOps,会把事务加入到fragmentManager的mBackStack列表中
    mAddToBackStack = true;
    //这是我们自己设置的名字,可以为null
    mName = name;
    return this;
}

popBackStackの機能

これが議論する最も簡単なfragmentManager.popBackStack()です

public void popBackStack() {
    //很熟悉的方法enqueueAction,也是向列表中提交事务,不过这里实例化了一个PopBackStackState对象,有必要看一下
    enqueueAction(new PopBackStackState(null, -1, 0), false);
}
private class PopBackStackState implements OpGenerator {
    final String mName;
    final int mId;
    final int mFlags;

    //PopBackStackState也实现了OpGenerator接口,目前name==null,id==-1,flag==0
    PopBackStackState(@Nullable String name, int id, int flags) {
        mName = name;
        mId = id;
        mFlags = flags;
    }
}

現在、popBackStackとaddおよびreplaceによって構築されるアクションは異なります。1つはBackStackRecordで、もう1つはPopBackStackStateです。

構築が完了すると、アクションがfragmentManagerのキューに入れられて実行されます。トランザクションのソースは異なり、generateOpsももちろん異なります。フローチャートのこの部分は次のようにエコーされます。

image.pngPopBackStackStateのgenerateOpsを見てください

@Override
public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
        @NonNull ArrayList<Boolean> isRecordPop) {
     //已省略...
     //目前name==null,id==-1,flag==0
    return popBackStackState(records, isRecordPop, mName, mId, mFlags);
}

コアはpopBackStackStateです。では、見てみましょう。

@SuppressWarnings({"unused", "WeakerAccess"}) /* synthetic access */
boolean popBackStackState(@NonNull ArrayList<BackStackRecord> records,
        @NonNull ArrayList<Boolean> isRecordPop, @Nullable String name, int id, int flags) {
    if (mBackStack == null) {
        return false;
    }
    //由于目前name==null,id==-1,flag==0所以会直接进入if的判断中
    if (name == null && id < 0 && (flags & POP_BACK_STACK_INCLUSIVE) == 0) {
        //这里直接把返回栈的最后一个数据放入records列表中并且isRecordPop的数据也为true
        int last = mBackStack.size() - 1;
        if (last < 0) {
            return false;
        }
        //需要注意这里保存的数据是之前提交的事务
        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;
}

これまでのところ、popBackStack()メソッドのデータが作成されており、次のプロセスが続行されます。

image.pngexecuteOpsメソッドでは、スタックからポップされているかどうかを判断します。ポップされている場合は、executePopOpsメソッドを実行します。

//BackStackRecord
//可以看出这里是和当前事务执行相反的操作,比如之前的事务的操作是OP_ADD
//这里判断到是case OP_ADD时是执行remove操作
void executePopOps(boolean moveToState) {
    for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
        final Op op = mOps.get(opNum);
        Fragment f = op.mFragment;
        if (f != null) {
            f.setPopDirection(true);
            f.setNextTransition(FragmentManager.reverseTransit(mTransition));
            // Reverse the target and source names for pop operations
            f.setSharedElementNames(mSharedElementTargetNames, mSharedElementSourceNames);
        }
        switch (op.mCmd) {
            case OP_ADD:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.setExitAnimationOrder(f, true);
                mManager.removeFragment(f);
                break;
            case OP_REMOVE:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.addFragment(f);
                break;
            case OP_HIDE:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.showFragment(f);
                break;

executeOpsが実行されると、すべての準備が終了し、後続の操作はaddと同じになります。フラグメントは、moveToExpectedStateを介して目的のライフサイクル状態に移動されます。

popBackStackシリーズのメソッドはpopBackStackStateを呼び出して構築recordsおよびisRecordPop一覧表示isRecordPopし、内部要素の値はすべてtrueです。後続のプロセスはcommitトランザクションと同じでありisRecordPopexecutePopOpsorexecuteOpsメソッドは異なる値に従って選択されます。

最後の要約:popBackStack(String name、int flag)の場合、名前はaddToBackStack(String name)のパラメーターです。popBackStack()のみを呼び出すと、名前はnullになり、フラグは0になります。バックスタックは名前で見つけることができます。フラグは0にすることができます。またはFragmentManager.POP_BACK_STACK_INCLUSIVE、0は、この要素より上のすべての要素のみがポップされ、この要素以上を含むすべての要素がポップされることを意味しPOP_BACK_STACK_INCLUSIVEます。ここに記載されているすべての要素のポップには、これらのトランザクションのロールバックが含まれます。詳細については、popBackStackStateメソッドのソースコードを参照してください。

おすすめ

転載: juejin.im/post/7117567128336597005