43be284cd40b65ffce0e453832823410.gif

这道题想考察什么?
  1. 是否熟悉add和replace的应用场景

  2. 是否熟悉Fragment的事务操作后的处理流程

考察的知识点
  1. add和replace的应用场景

  2. Fragment事务操作后的处理流程

考生应该如何回答

1、首先我们先从add和replace应用场景出发

当我们对Activity通过事务添加一个Fragment时,有两种方式都可以做到,那就是add和replace。

  • 当前Activity同一个容器只添加一个Fragment时add和replace效果是一样的。

  • 当前Activity添加了一个FragmentA后,在后续某个操作中要将这个FragmentA替换为另外一个FragmentB时,有两种情况:

  1. 如果 FragmentA是通过add添加的,在将 FragmentA替换为 FragmentB时,可以通过hide FragmentA,add FragmentB show FragmentB

  2. 如果 FragmentA通过replace操作添加的,在将 FragmentA替换为 FragmentB时,使用replace替换

  • 通过 add 添加的 Fragments,可以由开发者自由控制当前应该显示哪个Fragment,以及隐藏哪个Fragment,其实在源码中就是对应Fragment中View的显示和隐藏。

  • 通过replace 添加 的 Fragment,当前已存在的Fragment被替换时走生命周期销毁流程,传递给replace方法的Fragment走生命周期创建流程。

  • 根据以上结论,我们可以得到一个实例开发中添加Fragment时很重要的一个结论:

    • 当Fragment不可见时,如果你要保留Fragment中的数据以及View的显示状态,那么可以使用add操作,后续针对不同的状态隐藏和显示不同的Fragment。

    • 优点:快,支持Fragment中View的显示和隐藏

    • 缺点:内存中保留的数据太多,容易导致造成OOM的风险。

    • 当Fragment不可见时,你不需要保留Fragment中的数据以及View的显示状态,那么可以使用replace。

    • 优点:节省内存,不需要的数据能立即释放掉

    • 缺点:频繁创建Fragment,也就是频繁走Fragment生命周期创建和销毁流程,造成性能开销。

2、然后分别对进行一个add和replace事物操作时,源码中是如何处理的。

要对add和replace事务操作源码中是如何处理的,那么先看下对Fragment事务操作提交流程。

简要流程图:

f05761b00c1eec785eee2195f9feb52f.png

从流程图中发现当执行第10步骤,也就是当调用BackStackRecord#expandOps方法时,对replace操作会进行修正

//BackStackRecord#expandOpsFragment expandOps(ArrayList 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--) {                        //如果当前已有Fragment添加到Activity中,取出已添加的Fragment                        final Fragment old = added.get(i);                        if (old.mContainerId == containerId) {                            if (old == f) {                                //如果replace的是同一个Fragment                                alreadyAdded = true;                            } else {                                //不是同一Fragment,删除旧的Fragment                                final Op removeOp = new Op(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) {                        //从操作序列中移除当前请求的操作,表示当前操作无效                        mOps.remove(opNum);                        opNum--;                    } else {                        //当前Activity中同一个id没有添加Fragment或者同一个id存在Fragment,但replace传递fragment和已有的不是同一个实例,将操作类型replace修改为add                        op.cmd = OP_ADD;                        added.add(f);                    }                }                break;            }        }        return oldPrimaryNav;    }

由上面代码分析可知

1、如果当前Activity同一个id还没有添加Fragment,replace操作和add操作一样。

即执行两者操作生命周期变化:onAttach->onCreate->onCreateView->onActivityCreated->onStart-onResume,Fragment所依附的Activity销毁时,执行onPause->onStop->onDestoryView->onDestory->onDetach

2、如果当前Activity同一个id存在Fragment,replace传递的Fragment实例和已存在的Fragment实例一样,replace无效果,这点从上面源码中可以看出。

3、如果当前Activity同一个id存在Fragment,replace传递的Fragment实例和已存在的Fragment实例不一样,replace操作会转换为 remove和add操作,即删除旧的Fragment,添加新的Fragment,这点从上面代码中也可以看出来。

旧的Fragment执行 onPause->onStop->onDestoryView->onDestory->onDetach

新的Fragment执行 onAttach->onCreate->onCreateView->onActivityCreated->onStart-onResume

总的来说BackStackRecord#expandOps就是修正replace的操作,将replace 变为 remove和add操作。

无论是remove,add 我们发现操作的都是mOps集合。mOps中存放的是事务操作的序列。根据流程图在接下来第11步骤也就是BackStackRecord#executeOps会执行mOps存放的事务操作。

void executeOps() {    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);        }       ...    }    //执行Fragment生命周期    mManager.moveToState(mManager.mCurState, true);}

最后简单总计下:

面试官在问add和replace区别,我们可以从实际使用中真实感受出发 即第一点回答,描述完区别后;再来从源码角度描述replace本质是什么,replace本质就是将replace操作变为remove和add操作,旧的 Fragment走生命周期销毁流程,新传递的Fragment走生命周期创建流程。

53d72e88a8664f2bda3985fbd44ac117.png

437b652e3f0df3488ce01c12434ae248.gif分享、在看与点赞都在这儿点下给小编加点料438c13b3848e16ca3bafcd5099526458.gif
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐