Fragment management and kernel of Android component kernel, retrofit analysis

Set the FragmentManagerImpl of the fragment
Set the tag of the fragment
Set the mContainerId and mFragmentId of the fragment
Insert an op of type_ Add operation to the end of the linked list
A class is used here:

    static final class Op {
        Op next;//Next operation node
        Op prev;//Previous operation node
        int cmd;//Operation type: OP_NULL|OP_ADD|OP_REPLACE|OP_REMOVE|OP_HIDE|OP_SHOW|OP_DETACH|OP_ATTACH
        Fragment fragment;//Fragment object for operation
        int enterAnim;//Entrance animation
        int exitAnim;//Appearance animation
        int popEnterAnim;//Pop in animation
        int popExitAnim;//Pop up animation
        ArrayList<Fragment> removed;
    }

This is an operation linked list node. All add, remove, hide and other things will eventually form an operation chain

1.3.8FragmentTransaction#commit
After all operations are inserted, we finally need to call the commit method of FragmentTransaction before the operation can be really executed.

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

    int commitInternal(boolean allowStateLoss) {
        //Prevent duplicate commit
        if (mCommitted) {
            throw new IllegalStateException("commit already called");
        }

        //DEBUG code is ignored
        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;

        //This flag is true only after the addToBackStack method is called
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        //Insert transaction queue
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

1.3.9FragmentManagerImpl#enqueueAction

/**
   * Adds an action to the queue of pending actions.
   *
   * @param action the action to add
   * @param allowStateLoss whether to allow loss of state information
   * @throws IllegalStateException if the activity has been destroyed
   */
  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);
          }
      }
  }

Here, add the action to the mPendingActions list. Get the Handler through mHost.getHandler() and send the execution request. From the above analysis, mHost is the HostCallbacks of the Activity. The mHandler of the Activity is passed in the construction method. The mHost.getHandler() executed here obtains the mHandler in the Activity. This is because it needs to be executed in the main thread

final Handler mHandler = new Handler();

Let's look at what is done in mExecCommit:

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

    /**
     * Only call from main thread!
     */
    public boolean execPendingActions() {
        if (mExecutingActions) {
            throw new IllegalStateException("Recursive entry to executePendingTransactions");
        }

        //Check again whether the main thread
        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) {

                //Parameter detection
                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;
            //Traversal performs pending transaction operations
            for (int i=0; i<numActions; i++) {
                mTmpActions[i].run();
                mTmpActions[i] = null;
            }
            mExecutingActions = false;
            didSomething = true;
        }

        doPendingDeferredStart();

        return didSomething;
    }

After inserting things, the transactions to be processed are processed uniformly in the main thread. The transactions are processed by executing mTmpActions[i].run(). This mTmpActions[i] is the BackStackRecord we inserted through enqueueAction method. Children may not notice that it is a Runnable. Let's see its definition

final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, Runnable {
    static final String TAG = FragmentManagerImpl.TAG;
    ... ...
}

Around, we're back to BackStackRecord

1.3.10BackStackRecord#run

    public void run() {

        ......

        if (mManager.mCurState >= Fragment.CREATED) {
            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
            calculateFragments(firstOutFragments, lastInFragments);
            beginTransition(firstOutFragments, lastInFragments, false);
        }
        //Traverse the linked list and process transactions in turn according to the cmd transaction type
        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 = mManager.mAdded.size() - 1; i >= 0; i--) {
                            Fragment old = mManager.mAdded.get(i);
                            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;
                                    }
                                    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);
        }
    }

At this step, the committed transaction is actually executed. We know that even after committing the transaction, it is not executed synchronously, but sent to the main thread for execution through the Handler.

All transactions are processed in the run method, but we notice that we still need to know more about FragmentManagerImpl in order to find out what is really done behind add, remove and other transactions.
#2, Fragment transition animation
The transition animation implementation of Fragment can be divided into two cases: using v4 package and not using v4 package. If not using v4 package, the minimum API Level needs to be 11.

2.1 standard transition Animation:

You can assign a standard transition animation to the Fragment through the * * settransition (int transition) * * method.

The three parameters that can be passed in by this method are:

TRANSIT_NONE,

TRANSIT_FRAGMENT_OPEN,

TRANSIT_FRAGMENT_CLOSE

Corresponding to no animation, open animation and closed animation respectively.

After the standard animation is set, it will appear when the Fragment is added and removed.

2.2 custom transition animation

Custom transition animations are created through the setCustomAnimations() method. Because fragments can be specified to be added to the back stack when they are added, transition animations can be added, removed, pop ped out of the back stack, and entered.

Note that the setCustomAnimations() method must be set before the add, remove and replace calls, otherwise it will not work.

##2.3 android.app.Fragment

Class reference:

Fragment: [http://developer.android.com/reference/android/app/Fragment.html](

)

FragmentTransaction:[http://developer.android.com/reference/android/app/FragmentTransaction.html](

)

When the v4 package is not used (min API > = 11), the corresponding animation type is Property Animation.

That is, the animation resource file needs to be placed in the * res\animator * directory, and the root tag is one of the three.

This can also be seen from the method in the Fragment: [onCreateAnimator](

))(int transit, boolean enter, int nextAnim), the return value is [Animator](

).

When customizing transition animation, the four parameter form setCustomAnimations (int enter, int exit, int popEnter, int popExit) is unique to API Level 13. 11 only introduces two animation forms, that is, transition animation during Back Stack operation cannot be specified.

Code example:


#### Is there anything you must master in addition to flutter for Android development?

Believe that most people are engaged in Android Development friends are finding it more and more difficult to find a job and the requirements of interview are higher and higher

In addition to solid foundation java Knowledge, data structures, algorithms, design patterns, and the underlying source code, NDK Technology, performance tuning, and some small programs and cross platforms, for example flutter´╝îIt is shown in the following figure in the form of mind map;

**[CodeChina Open source projects:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](

)**

![](https://img-blog.csdnimg.cn/img_convert/6e9a3582d093c74d79a2fdc22f836ef8.png)



> **This article has been[tencent CODING Open source hosting project:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](https://ali1024.coding.net/public/P7/Android/git), self-study resources and series of articles are constantly updated**
va Knowledge, data structures, algorithms, design patterns, and the underlying source code, NDK Technology, performance tuning, and some small programs and cross platforms, for example flutter´╝îIt is shown in the following figure in the form of mind map;

**[CodeChina Open source projects:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](

)**

[External chain picture transfer...(img-pVuYwIUr-1631243105704)]



> **This article has been[tencent CODING Open source hosting project:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](https://ali1024.coding.net/public/P7/Android/git), self-study resources and series of articles are constantly updated**

Tags: Android Design Pattern Programmer

Posted on Sun, 21 Nov 2021 02:39:15 -0500 by TangoGirl