[Android] Fragment source code analysis (3) Transactions

Source: Internet
Author: User

[Android] Fragment source code analysis (3) Transactions

In Fragment management, we have to talk about its transaction management. Its transaction management is very brilliant. First, we introduce a simple and common Fragment transaction management code snippet:

            FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();            ft.add(R.id.fragmentContainer, fragment, "tag");            ft.addToBackStack("tag");            ft.commitAllowingStateLoss();

After this code is executed, you can add the Fragment internal control to the fragmentContainer control. In the previous section, we talked about Fragment generating internal mviews through state machine changes. When you use the non-from layout. xml method, it searches for the control corresponding to the iner In the Fragment. CREATED state and then adds the mView to the parent control. So what role does this transaction play?

Let's first look at the return value of Manager. beginTransaction:

/**     * Start a series of edit operations on the Fragments associated with this     * FragmentManager.     *     * 

* Note: A fragment transaction can only be created/committed prior to an * activity saving its state. If you try to commit a transaction after * {@link FragmentActivity#onSaveInstanceState * FragmentActivity.onSaveInstanceState()} (and prior to a following * {@link FragmentActivity#onStart FragmentActivity.onStart} or * {@link FragmentActivity#onResume FragmentActivity.onResume()}, you will * get an error. This is because the framework takes care of saving your * current fragments in the state, and if changes are made after the state * is saved then they will be lost. *

*/ public abstract FragmentTransaction beginTransaction();
In Fragment management, the implementation class of FragmentManager is FragmentManagerImpl, which is also the consistent naming method of Android;

FragmentManagerImpl.java:@Override    public FragmentTransaction beginTransaction() {        return new BackStackRecord(this);    }

FragmentManager returns an object called BackStackRecord to complete transaction processing. Aside from Android itself, our understanding of transactions mainly comes from the database, which is a batch operation. Record your operation set and then process it all at once, ensures the security and efficiency of transactions. FragmentManager also holds the same view of transactions. The core method of BackStackRecord is addOp (Op ):

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

We can see that the organizations that BackStackRecord processes operations adopt the "iterator" mode. Each operation is recorded as an Op object and can be viewed as a "Memorandum" mode. The entry to the add operation:

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

Is organized in the form of "Builder. At the beginning of this article, I have mentioned that Fragment's transaction management is a brilliant code. Simple transactions are organized in at least three sets of modes, and they are not organized at all. Of course, Fragment brings us more than just that. We can see from the above code snippets that, in fact, the Op object generated through the transaction class BackStackRecord is actually copying the attributes of BackStackRecord. So when we analyze the data in each Op, you can use the property ing in BackStackRecord directly.

Int mNumOp; // Number of Op int mEnterAnim; // enter the animation int mPopEnterAnim; // exit the animation int mPopEnterAnim; // enter the animation int mPopExitAnim; // The exit animation int mTransition pops up; // transfer animation int mTransitionStyle; boolean mAddToBackStack; // Add to BackStack

Op itself belongs to the Command mode. Its Command list is:

    static final int OP_NULL = 0;    static final int OP_ADD = 1;    static final int OP_REPLACE = 2;    static final int OP_REMOVE = 3;    static final int OP_HIDE = 4;    static final int OP_SHOW = 5;    static final int OP_DETACH = 6;    static final int OP_ATTACH = 7;

You may have seen that, yes, the Op attribute is used as the operand of the Command. After the BackStackRecord is committed, the BackStackRecord will include itself in the FragmentManagerImpl command queue for processing. Each processing unit is used to process its own Op operations. Let's take a look at the Code:

BackStackRecord.java: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;    }

BackStackRecord submits itself to the Action queue of the mManager when it is submitted. This Action queue can be processed in any thread.

FragmentManager.java: public void enqueueAction(Runnable action, boolean allowStateLoss) {        if (!allowStateLoss) {            checkStateLoss();        }        synchronized (this) {            if (mActivity == null) {                throw new IllegalStateException("Activity has been destroyed");            }            if (mPendingActions == null) {                mPendingActions = new ArrayList
 
  ();            }            mPendingActions.add(action);            if (mPendingActions.size() == 1) {                mActivity.mHandler.removeCallbacks(mExecCommit);                mActivity.mHandler.post(mExecCommit);            }        }    }
 

We can see that Action is actually executed by the mExecCommit command, which calls back the run method of the BackStackRecord you submitted.

BackStackRecord.java:       Op op = mHead;        while (op != null) {             ...        }

We can see that the command runs cyclically as an iterator. Different commands have different status change operations on Fragment. For example:

Op.java:case OP_ADD: {                    Fragment f = op.fragment;                    f.mNextAnim = op.enterAnim;                    mManager.addFragment(f, false);                } break;

When we need to Add a Fragment, Op will call the addFragment method of FragmentManager.

FragmentManager.java:public void addFragment(Fragment fragment, boolean moveToStateNow) {        if (mAdded == null) {            mAdded = new ArrayList
 
  ();        }        makeActive(fragment);        if (!fragment.mDetached) {            if (mAdded.contains(fragment)) {                throw new IllegalStateException("Fragment already added: "                        + fragment);            }            mAdded.add(fragment);            fragment.mAdded = true;            fragment.mRemoving = false;            if (fragment.mHasMenu && fragment.mMenuVisible) {                mNeedMenuInvalidate = true;            }            if (moveToStateNow) {                moveToState(fragment);            }        }    }
 

FragmentManager adds it to its mAdded queue first, and then changes the Fragment state by calling the moveToState method to ensure consistency in the state. This part is the content of the previous part. We will not repeat it here. In this way, Fragment implements transaction processing in this elegant way. In the next article, I will describe part of Fragment's source code for Stack management.





Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.