Title: Difference between Fragment Add and replace, impact on Fragment lifecycle

What is this question about?

  1. Are you familiar with the application scenarios of Add and replace
  2. Whether you are familiar with the process after the Fragment transaction operation

Knowledge points investigated

  1. Application scenarios of Add and replace
  2. Process after a Fragment transaction

How should the examinee answer

  1. Let’s start with the Add and Replace scenarios

    When adding a Fragment to an Activity through a transaction, there are two ways to do it: add and replace.

    • Add and replace have the same effect when you add only one Fragment to an Activity container.
    • The current Activity adds a FragmentA after the FragmentASubsequent operationWhen you want to replace this FragmentA with another FragmentB, there are two situations:
      1. ifFragmentAIs added by addFragmentAReplace withFragmentB“, you can run the hide commandFragmentA, the addFragmentB show FragmentB
      2. ifFragmentAAdded by the replace operation in theFragmentAReplace withFragmentB“, replace with replace
    • Added by addFragments, the developer can control which Fragment should be displayed and which Fragment should be hidden. In fact, in the source code, the View in the corresponding Fragment should be displayed and hidden.
    • With the Fragment added by replace, the existing Fragment is replaced with a life-cycle destruction process, which is passed to the Fragment life-cycle creation process of the replace method.
    • Based on the above conclusions, we can draw a conclusion that adding fragments is very important in instance development
      • When the Fragment is not visible, if you want to preserve the data in the Fragment and the View’s display state, you can use the Add operation. Later, you can hide and display different fragments for different states.
        • Advantages: fast, knowledge Fragment View display and hide
        • Disadvantages: Too much data is stored in the memory, which may cause OOM risk.
      • When the Fragment is invisible, you don’t need to preserve the data in the Fragment and the View’s display state. Replace can be used instead.
        • Advantages: Saves memory and releases unwanted data immediately
        • Disadvantages: Frequent creation of fragments, i.e. frequent creation and destruction of the Fragment lifecycle, incurs performance overhead.
  2. And then to do an add and replace thing operation respectively, how to deal with the source code.

    To see how add and replace transactions are handled in the source code, take a look at the commit process for Fragment transactions.

    Brief flow chart

    Click for a larger version

    You can see from the flowchart that the replace operation is modified when step 10 is performed, when the BackStackRecord#expandOps method is called

    //BackStackRecord#expandOps
    Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
            for (int opNum = 0; opNum < mOps.size(); opNum++) {
                final Op op = mOps.get(opNum);
                switch (op.cmd) {
                    case OP_ADD:
                    case OP_ATTACH:
                        added.add(op.fragment);
                        break;      
                    case OP_REMOVE:
                    case OP_DETACH: {
                        added.remove(op.fragment);
                    }
                    case OP_REPLACE: {
                        final Fragment f = op.fragment;
                        final int containerId = f.mContainerId;
                        boolean alreadyAdded = false;
                        for (int i = added.size() - 1; i >= 0; i--) {
                            // If an existing Fragment is added to the Activity, fetch the added Fragment
                            final Fragment old = added.get(i);
                            if (old.mContainerId == containerId) {
                                if (old == f) {
                                    // If replace is the same Fragment
                                    alreadyAdded = true;
                                } else {
                                    // Delete the old Fragment that is not the same Fragment
                                    final Op removeOp = newOp(OP_REMOVE, old); removeOp.enterAnim = op.enterAnim; removeOp.popEnterAnim = op.popEnterAnim; removeOp.exitAnim = op.exitAnim; removeOp.popExitAnim = op.popExitAnim; mOps.add(opNum, removeOp); added.remove(old); opNum++; }}}if (alreadyAdded) {
                            // Remove the currently requested operation from the operation sequence, indicating that the current operation is invalid
                            mOps.remove(opNum);
                            opNum--;
                        } else {
                            // In the current Activity, there is no Fragment added to the same ID or the same ID has a Fragment, but replace passes the Fragment and the existing instance is not the same, change the operation type of replace to addop.cmd = OP_ADD; added.add(f); }}break; }}return oldPrimaryNav;
        }
    Copy the code

    From the above code analysis

    1. If the current Activity has no Fragment added to it, the replace operation is the same as the add operation.

      OnAttach ->onCreate->onCreateView->onActivityCreated->onStart-onResume

      When the Fragment is destroyed, execute onPause->onStop->onDestoryView->onDestory->onDetach

    2. If the current Activity has a Fragment with the same ID, the Fragment instance passed by replace is the same as the existing Fragment instance. Replace has no effect, as can be seen from the above source code

    3. If the Activity has a Fragment with the same ID and the Fragment instance passed by replace is different from the existing Fragment instance, the replace operation is converted to remove and add operations. Remove old fragments and add new ones, as can be seen in the code above.

      The old Fragment executes onPause->onStop->onDestoryView->onDestory->onDetach

      Execute onAttach->onCreate->onCreateView->onActivityCreated->onStart-onResume for the new Fragment

    In general, BackStackRecord#expandOps fixes replace to remove and add.

    Whether it’s remove or add we find that we’re operating on a collection of mOps. MOps stores sequences of transaction operations. BackStackRecord#executeOps will execute the mOps stored transaction.

    void executeOps(a) {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            final Fragment f = op.fragment;
            switch (op.cmd) {
                case OP_ADD:
                    f.setNextAnim(op.enterAnim);
                    mManager.addFragment(f, false);
                    break;
                case OP_REMOVE:
                    f.setNextAnim(op.exitAnim);
                    mManager.removeFragment(f);
                    break;
                case OP_HIDE:
                    f.setNextAnim(op.exitAnim);
                    mManager.hideFragment(f);
                    break;
                case OP_SHOW:
                    f.setNextAnim(op.enterAnim);
                    mManager.showFragment(f);
                    break;
                case OP_DETACH:
                    f.setNextAnim(op.exitAnim);
                    mManager.detachFragment(f);
                    break;
                case OP_ATTACH:
                    f.setNextAnim(op.enterAnim);
                    mManager.attachFragment(f);
                    break;
                case OP_SET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(f);
                    break;
                case OP_UNSET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(null);
                    break;
                default:
                    throw new IllegalArgumentException("Unknown cmd: "+ op.cmd); }... }// Execute the Fragment life cycle
        mManager.moveToState(mManager.mCurState, true);
    }
    Copy the code
    1. Finally, a brief summary:

      When the interviewer asks the difference between add and replace, we can start from the real feeling in the actual use. The essence of replace is to change replace operations into remove and add operations. The old Fragment life cycle destruction process and the new Fragment life cycle creation process are passed.

      If you need a more detailed answer from the source point of view, you can answer:

      1. If the current Activity has no Fragment added to it, the replace operation is the same as the add operation.

        OnAttach ->onCreate->onCreateView->onActivityCreated->onStart-onResume

        When the Fragment is destroyed, execute onPause->onStop->onDestoryView->onDestory->onDetach

      2. If the Activity has a Fragment with the same ID, the Fragment instance passed by replace is the same as the existing Fragment instance, and the replace has no effect.

      3. If the Activity has a Fragment with the same ID and the Fragment instance passed by replace is different from the existing Fragment instance, the replace operation is converted to remove and add operations. Delete old fragments and add new ones.

        The old Fragment executes onPause->onStop->onDestoryView->onDestory->onDetach

        Execute onAttach->onCreate->onCreateView->onActivityCreated->onStart-onResume for the new Fragment

    This article is in the open source project: github.com/Android-Alv… Has been included, which contains different directions of self-study programming routes, interview questions set/interviews, and a series of technical articles, etc., resources continue to update…