Fragment相关源码阅读笔记(2)FragmentTransaction

Fragment的管理中使用了事务的概念,类似于数据库中的事务,可以把对Fragment操作打包成事务提交,(API for performing a set of Fragment operations)
,通过FragmentTransaction的addToBackStack和FragmentManager的popBackStack可以进行事务入栈和回滚操作

1.FragmentTransaction对象

我们一般通过FragmentManager的beginTransaction()获取FragmentTransaction对象,但FragmentTransaction是一个抽象类,我们实际拿到的是一个什么样的对象,getFragmentManager()获取的是FragmentManagerImpl对象

FragmentManagerImpl的方法实现

public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}
我们调用beginTransaction,实际是拿到了一个BackStackRecord对象
看一下BackStackRecord的继承结构
Entry of an operation on the fragment back stack.
final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, Runnable 

BackStackRecord继承自FragmentTransaction,此外还实现了两个接口:FragmentManager.BackAtackEntry,Runnable
1.FragmentManager.BackAtackEntry是对Fragment事务栈管理的对象的抽象,在HashMap中有类似的Entry概念。
我们每次获取FragmentTransaction 对象并commit都是进行一次Fragment事务的提交,事务由FragmentManager管理
   
* Representation of an entry on the fragment back stack, as created
* with {@link FragmentTransaction#addToBackStack(String)
* FragmentTransaction.addToBackStack()}.  Entries can later be
* retrieved with {@link FragmentManager#getBackStackEntryAt(int)
* FragmentManager.getBackStackEntryAt()}.
*
* <p>Note that you should never hold on to a BackStackEntry object;
* the identifier as returned by {@link #getId} is the only thing that
* will be persisted across activity instances.
2.Runnable接口
  实现了Runnable接口说明BackStackRecord是一个可执行对象,这也是Fragment原理中比较关键的一点,正式使用Handler对Fragment事务进行了调度执行。
   看一下FragmentTransaction的commit方法
public int commit() {
    return commitInternal(false);
}

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) {
        throw new IllegalStateException("commit already called");
    }
    if (FragmentManagerImpl.DEBUG) {
        Log.v(TAG, "Commit: " + this);
        LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
        PrintWriter pw = new FastPrintWriter(logw, false, 1024);
        dump("  ", null, pw, null);
        pw.flush();
    }
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}
FragmentManager把事务入队mPendingActions,并通过主线程调度mExecCommit,执行execPendingActions方法,该方法调用了BackStackRecord的run方法
public void enqueueAction(Runnable action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        checkStateLoss();
    }
    synchronized (this) {
        if (mDestroyed || mHost == null) {
            throw new IllegalStateException("Activity has been destroyed");
        }
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<Runnable>();
        }
        mPendingActions.add(action);
        if (mPendingActions.size() == 1) {
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
        }
    }
}
Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};
public boolean execPendingActions() {
    if (mExecutingActions) {
        throw new IllegalStateException("Recursive entry to executePendingTransactions");
    }
    
    if (Looper.myLooper() != mHost.getHandler().getLooper()) {
        throw new IllegalStateException("Must be called from main thread of process");
    }

    boolean didSomething = false;

    while (true) {
        int numActions;
        
        synchronized (this) {
            if (mPendingActions == null || mPendingActions.size() == 0) {
                break;
            }
            
            numActions = mPendingActions.size();
            if (mTmpActions == null || mTmpActions.length < numActions) {
                mTmpActions = new Runnable[numActions];
            }
            mPendingActions.toArray(mTmpActions);
            mPendingActions.clear();
            mHost.getHandler().removeCallbacks(mExecCommit);
        }
        
        mExecutingActions = true;
        for (int i=0; i<numActions; i++) {
            mTmpActions[i].run();
            mTmpActions[i] = null;
        }
        mExecutingActions = false;
        didSomething = true;
    }

   ```````
    return didSomething;
}

现在看一下BackStackRecord的run方法干了什么

public void run() {
    if (FragmentManagerImpl.DEBUG) {
        Log.v(TAG, "Run: " + this);
    }

    if (mAddToBackStack) {
        if (mIndex < 0) {
            throw new IllegalStateException("addToBackStack() called after commit()");
        }
    }

    bumpBackStackNesting(1);

    SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
    SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
    calculateFragments(firstOutFragments, lastInFragments);
    beginTransition(firstOutFragments, lastInFragments, false);

    Op op = mHead;
    while (op != null) {
        switch (op.cmd) {
            case OP_ADD: {
                Fragment f = op.fragment;
                f.mNextAnim = op.enterAnim;
                mManager.addFragment(f, false);
            }
            break;
            case OP_REPLACE: {
                Fragment f = op.fragment;
                int containerId = f.mContainerId;
                if (mManager.mAdded != null) {
                    for (int i = 0; i < mManager.mAdded.size(); i++) {
                        Fragment old = mManager.mAdded.get(i);
                        if (FragmentManagerImpl.DEBUG) {
                            Log.v(TAG,
                                    "OP_REPLACE: adding=" + f + " old=" + old);
                        }
                        if (old.mContainerId == containerId) {
                            if (old == f) {
                                op.fragment = f = null;
                            } else {
                                if (op.removed == null) {
                                    op.removed = new ArrayList<Fragment>();
                                }
                                op.removed.add(old);
                                old.mNextAnim = op.exitAnim;
                                if (mAddToBackStack) {
                                    old.mBackStackNesting += 1;
                                    if (FragmentManagerImpl.DEBUG) {
                                        Log.v(TAG, "Bump nesting of "
                                                + old + " to " + old.mBackStackNesting);
                                    }
                                }
                                mManager.removeFragment(old, mTransition, mTransitionStyle);
                            }
                        }
                    }
                }
                if (f != null) {
                    f.mNextAnim = op.enterAnim;
                    mManager.addFragment(f, false);
                }
            }
            break;
            case OP_REMOVE: {
                Fragment f = op.fragment;
                f.mNextAnim = op.exitAnim;
                mManager.removeFragment(f, mTransition, mTransitionStyle);
            }
            break;
            case OP_HIDE: {
                Fragment f = op.fragment;
                f.mNextAnim = op.exitAnim;
                mManager.hideFragment(f, mTransition, mTransitionStyle);
            }
            break;
            case OP_SHOW: {
                Fragment f = op.fragment;
                f.mNextAnim = op.enterAnim;
                mManager.showFragment(f, mTransition, mTransitionStyle);
            }
            break;
            case OP_DETACH: {
                Fragment f = op.fragment;
                f.mNextAnim = op.exitAnim;
                mManager.detachFragment(f, mTransition, mTransitionStyle);
            }
            break;
            case OP_ATTACH: {
                Fragment f = op.fragment;
                f.mNextAnim = op.enterAnim;
                mManager.attachFragment(f, mTransition, mTransitionStyle);
            }
            break;
            default: {
                throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
            }
        }

        op = op.next;
    }

    mManager.moveToState(mManager.mCurState, mTransition,
            mTransitionStyle, true);

    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
}

run方法遍历了一个操作命令链表,对每一个命令分别调用对应的FragmentManager方法执行对应的操作(以及transitions相关的操作和事务入栈操作)
这个命令链表是如何得到的呢?BackStackRecord还继承了FragmentTransaction,这了由对Fragment的各种操作add/replace/show/hide/remove
3.FragmentTransaction抽象类,以add实现为例:操作方法实现会调用doAddOp方法,创建一个Op对象添加到事务的操作链表里,Op是对Fragment操作进行的抽象
主要有操作类型和目标Fragment
public FragmentTransaction add(int containerViewId, Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
    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 (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;


    addOp(op);
}
void addOp(Op op) {

    } else {
        op.prev = mTail;
        mTail.next = op;
        mTail = op;
    }
    op.enterAnim = mEnterAnim;
    op.exitAnim = mExitAnim;
    op.popEnterAnim = mPopEnterAnim;
    op.popExitAnim = mPopExitAnim;
    mNumOp++;
}

总结:FragmentTransaction是Fragment事务操作的体现,FragmentTransaction本身的操作方法只是对事务操作命令的保存,
具体的实现是在commit时,提交给主线程消息处理机制去执行具体的Fragment操作。
} Op op = new Op(); op.cmd = opcmd; op.fragment = fragment;
    if (mHead == null) {
        mHead = mTail = op;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值