IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Fragment(一)从源码角度看add和replace过程 -> 正文阅读

[移动开发]Fragment(一)从源码角度看add和replace过程

Fragment(一)从源码角度看add和replace过程

博客对应的Demo地址:GitHubGitee

通过这篇博客,我们能知道以下问题:

  • Fragment add()replace() 方法差别
  • 从源码角度分析 add()replace() 方法

1. Fragment add()replace() 方法差别

add() 是添加 Fragment 到容器布局中,再搭配事务对象(FragmentTransaction)的 show()hide() 方法来显示和隐藏 Fragmentreplace()顾名思义“替换”,会销毁布局容器内的已有 Fragment,然后重新创建一个新的 Fragment 显示到布局容器中。通过一下两种方式的生命周期方式对比:

add-show/hide 方式生命周期:
1-1
replace 方式生命周期:
1-2

我们可以发现,replace() 方式替换的,被替换的Fragment会被彻底销毁,新的会重新创建,每一次的加载到界面到从界面消失的过程都是一个完整的生命周期;而 add() 结合 show()/hide() 方式的Fragment,切换时并不会彻底销毁 Fragment,而是走了 onHiddenChanged() 回调方法,改变了对用户的可见性,同时注意,这个方法并不是生命周期方法。他是在FragmentTransaction调用 show()hide() 方法时才会回调的方法。

注意:如果将Fragment加入回退栈

  • 对于add方式,生命周期方法回调无影响

  • 对于 replace 方式,那么他在被替换的时候是不会走销毁的方法的,它的生命周期方法如下:
    1-3

    ======================= 回退栈的使用说明 =======================

      private fun changeShowFragment(showFragment: Fragment) {
          supportFragmentManager.beginTransaction()
              .replace(R.id.fl_content, showFragment)
      		// 将Fragment增加到回退栈,并指定回退栈的名称为 replaceFragment
              .addToBackStack("replaceFragment")
              .commitAllowingStateLoss()
      }
    
      // 重写返回按钮
      override fun handlerOnBack() {
      	// 判断回退栈是否有未出栈的Fragment
          if(supportFragmentManager.backStackEntryCount > 1){
              supportFragmentManager.popBackStack()
          }else {
              super.handlerOnBack()
          }
      }
    

    ======================= 回退栈的使用说明 结束 =======================

2. 从源码角度分析 add()replace() 方法

上面从打印结果知道了 add()replace() 的差别,这一小节,我们从源码的角度来分析、查看系统对各个方法的调用过程。

说明:源码版本是 AndroidX库,具体 androidx.fragment:1.3.4 版本

FragmentManagerFragmentTransaction 的获取

FragmentActivity 中获取 FragmentManagerFragmentTransaction

首先看看 FragmentManagerFragmentTransaction 的获取

  • FragmentActivity 中获取 FragmentManager

      final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    
      @NonNull
      public FragmentManager getSupportFragmentManager() {
          return mFragments.getSupportFragmentManager();
      }
    

    通过 mFragments 获取, mFragments 就是 FragmentController,也是 FragmentActivity 的一个成员变量,通过静态方法创建,并且传递了 HostCallbacks 对象(注意:HostCallbacks extends FragmentHostCallback,HostCallbacks继承至FragmentHostCallback),这个对象就是后面会使用到的 mHost。具体创建过程如下:

      @NonNull
      public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
          return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
      }
    
      // 构造私有,通过静态方法创建,并且为 mHost 赋值
      private FragmentController(FragmentHostCallback<?> callbacks) {
          mHost = callbacks;
      }
    

    FragmentActivity中调用 getSupportFragmentManager() 方法,具体是调用 mFragments.getSupportFragmentManager() 方法。所以我们看一下 FragmentController (上面说过了 mFragments 就是 FragmentController)的 getSupportFragmentManager() 方法:

      @NonNull
      public FragmentManager getSupportFragmentManager() {
          return mHost.mFragmentManager;
      }
    

    直接取的是 mHost的变量 mFragmentManagermHost 就是前面传递进来的 HostCallbacks 对象,那么我们看看这个变量是什么:

      final FragmentManager mFragmentManager = new FragmentManagerImpl();
    

    这个变量实际上是在 FragmentHostCallback 定义的,前面我们说过 HostCallbacks 继承至 FragmentHostCallback ,取到 FragmentHostCallback 类中是没有问题的。看名字应该是一个 FragmentManager 的实现类。具体定义如下:

      class FragmentManagerImpl extends FragmentManager {
      }
    

    没错,确实是继承 FragmentManager ,但是类中没有任何具体的方法,FragmentManager 本身是抽象的,不能创建对象,所以通过一个实现类来创建实例。

  • FragmentActivity 中获取 FragmentTransaction
    通过以上分析,我们知道了在Activity中获取到的 FragmentManager 就是 FragmentManagerImpl 对象,那么我们在来看看 FragmentTransaction 是怎样取的,他是通过 FragmentManager 取的,也就是 FragmentManagerImpl 对象调用beginTransaction() 方法的返回值,通过前面我们知道这个方法实际上是在 FragmentManager 实现的,所以看看 FragmentManager 中的 beginTransaction() 方法:

      @NonNull
      public FragmentTransaction beginTransaction() {
          return new BackStackRecord(this);
      }
    

    很简单,直接创建了一个 BackStackRecord 对象返回,看看 BackStackRecord 类的定义:

      final class BackStackRecord extends FragmentTransaction implements
      FragmentManager.BackStackEntry, FragmentManager.OpGenerator
    

到了这里,FragmentActivity 中获取 FragmentManagerFragmentTransaction 的过程已经知道了,那么接下来看看在 Fragment 中获取 FragmentManagerFragmentTransaction 的过程。

Fragment 中获取 FragmentManagerFragmentTransaction

  • Fragment 中获取 FragmentManager
    Fragment 中获取 FragmentManager,是通过 getChildFragmentManager() 方法,看一下 Fragment 中这个方法的定义:

      @NonNull
      final public FragmentManager getChildFragmentManager() {
          if (mHost == null) {
              throw new IllegalStateException("Fragment " + this + " has not been attached yet.");
          }
          return mChildFragmentManager;
      }
    

    直接返回了 mChildFragmentManager 对象,看看这个对象的定义:

      FragmentManager mChildFragmentManager = new FragmentManagerImpl();
    

    直接创建了 FragmentManagerImpl 对象,赋值给父类 FragmentManager,这个类我们前面已经说过了。

  • Fragment 中获取 FragmentTransaction
    既然FragmentManager对象是 FragmentManagerImpl ,和 FragmentActivity 中一样,那么通过 FragmentManager 获取FragmentTransaction也就是相同的了,这里就不再重复了。

扩展

通过前面的了解,我们知道了 FragmentController 中的 mHost 就是在创建 FragmentController 时传递进来的 HostCallbacks 对象,我们现在来看看 Fragment 中的 mHost 是在哪里定义的。

通过查看源码,我们发现 Fragment 中的 mHost 的赋值位置是在 FragmentLayoutInflaterFactory 类的 onCreateView() 方法中,这个方法被调用的过程是:

  • FragmentActivity#onCreateView() -> FragmentActivity#dispatchFragmentsOnCreateView() -> FragmentController#onCreateView() -> FragmentLayoutInflaterFactory#onCreateView()

FragmentLayoutInflaterFactory#onCreateView() 中有这样一行代码:

fragment.mHost = mFragmentManager.getHost();

其中的 mFragmentManager 是在构造方法中传递进来的

FragmentLayoutInflaterFactory(FragmentManager fragmentManager) {
    mFragmentManager = fragmentManager;
}

FragmentLayoutInflaterFactory 的创建位置在 FragmentManager 中:

private final FragmentLayoutInflaterFactory mLayoutInflaterFactory =
        new FragmentLayoutInflaterFactory(this);

作为 FragmentManager 的一个全局成员变量,并且将 this 传递给 FragmentLayoutInflaterFactory,所以最终 Fragment 中的 mHost 就是 FragmentManager 中的 getHost() 方法返回值:

@NonNull
FragmentHostCallback<?> getHost() {
    return mHost;
}

FragmentManager 中的 mHost 赋值位置在 FragmentManager 中的 attachController() 方法中(篇幅原因,同时方法中的内容不是这里关注的重点,具体方法内容就不放进来了),而这个方法的调用位置有两个:一个是 Activity 中调用,一个在 Fragment 中调用,这也是很好理解的,因为Fragment中还可以嵌套Fragment,那么子Fragment中的 mHost 从哪里来了,就需要从父Fragment中来了。具体的调用流程如下:

  • Activity:FragmentActivity()构造 -> FragmentActivity#init() -> FragmentController#attachHost() -> FragmentManager#attachController()
  • Fragment:Fragment#performAttach()(该方法中还会调用Fragment的onAttach()方法,它的调用位置就不再这里说了) -> FragmentManager#attachController()

Activity的调用流程中,传递的就是在 FragmentActivity 中创建的 HostCallbacks 对象,在 Fragment 中保存;在 Fragment的调用流程中,Fragment#performAttach() 方法传递了当前的成员变量 mHost,而这个变量值就是 Activity 中传递过来的。 也就是说,就是在同一个 Activity 中的所有 Fragment 都是共用一个 FragmentController

到这里,我们就将 add()replace() 过程的使用到的部分类有了一定的了解了,接下来就看看这两种方式的具体流程。

add()-> show()/hide()

supportFragmentManager.beginTransaction()
        .add(R.id.fl_content, addFragment1)
        .add(R.id.fl_content, addFragment2)
        .commitAllowingStateLoss()

supportFragmentManager.beginTransaction()
    .show(showFragment)
    .hide(hideFragment)
    .commitAllowingStateLoss()

add()

add() 方法是属于 FragmentTransaction 类,我们看一下具体的代码,其中有多个重载方法

@NonNull
public final FragmentTransaction add(@NonNull Class<? extends Fragment> fragmentClass,
        @Nullable Bundle args, @Nullable String tag)  {
	// 调用 createFragment() 方法,创建Fragment实例对象,然后调用重载方法
    return add(createFragment(fragmentClass, args), tag);
}

@NonNull
public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)  {
	// 调用 doAddOp() 方法,传递 OP_ADD 参数
    doAddOp(0, fragment, tag, OP_ADD);
    return this;
}

@NonNull
public final FragmentTransaction add(@IdRes int containerViewId,
        @NonNull Class<? extends Fragment> fragmentClass, @Nullable Bundle args)  {
	// 调用重载方法
    return add(containerViewId, createFragment(fragmentClass, args));
}

@NonNull
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
	// 调用 doAddOp() 方法,传递 OP_ADD 参数
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

@NonNull
public final FragmentTransaction add(@IdRes int containerViewId,
        @NonNull Class<? extends Fragment> fragmentClass,
        @Nullable Bundle args, @Nullable String tag) {
	// 调用重载方法
    return add(containerViewId, createFragment(fragmentClass, args), tag);
}

@NonNull
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
        @Nullable String tag) {
	// 调用 doAddOp() 方法,传递 OP_ADD 参数
    doAddOp(containerViewId, fragment, tag, OP_ADD);
    return this;
}

FragmentTransaction add(@NonNull ViewGroup container, @NonNull Fragment fragment,
        @Nullable String tag) {
    fragment.mContainer = container;
	// 调用重载方法
    return add(container.getId(), fragment, tag);
}

======================= 针对上面 add() 方法的一个说明:=======================

  1. 以上就是 add() 的各个方法,他们最终调用的都是 doAddOp() 方法,并且传递了容器id,Fragment对象,tagOP_ADD 参数(重点注意OP_ADD参数,

  2. createFragment() 方法的作用是根据 FragmentClass 创建对象

     @NonNull
     private Fragment createFragment(@NonNull Class<? extends Fragment> fragmentClass,
             @Nullable Bundle args) {
     	// 调用 FragmentFactory#instantiate() 方法
         Fragment fragment = mFragmentFactory.instantiate(mClassLoader, fragmentClass.getName());
         if (args != null) {
     		// 设置参数
             fragment.setArguments(args);
         }
         return fragment;
     }
    

    FragmentFactory#instantiate() 方法

     @NonNull
     public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
         try {
     		// 通过反射创建对象,Fragment 必须有无参构造,否则会报错
             Class<? extends Fragment> cls = loadFragmentClass(classLoader, className);
             return cls.getConstructor().newInstance();
         } catch (Exception e) {
         }
     }
    

======================= 针对上面 add() 方法的一个说明结束 =======================

继续查看 FragmentTransaction#doAddOp() 方法

// FragmentTransaction#doAddOp()
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    final Class<?> fragmentClass = fragment.getClass();
    final int modifiers = fragmentClass.getModifiers();
   	// 省略对参数进行判断
	// 调用 addOp() 方法,这里的 opcmd 参数实际上就是 OP_ADD
    addOp(new Op(opcmd, fragment));
}

// FragmentTransaction#addOp()
void addOp(Op op) {
    mOps.add(op);
    op.mEnterAnim = mEnterAnim;
    op.mExitAnim = mExitAnim;
    op.mPopEnterAnim = mPopEnterAnim;
    op.mPopExitAnim = mPopExitAnim;
}

Op 类的定义

static final class Op {
    int mCmd; // 操作类型 可选有:OP_NULL|OP_ADD|OP_REPLACE|OP_REMOVE|OP_HIDE|OP_SHOW|OP_DETACH|OP_ATTACH
    Fragment mFragment; // 操作的Fragment对象
    int mEnterAnim; // 如此动画
    int mExitAnim;  // 退出动画
    int mPopEnterAnim; // 弹入动画
    int mPopExitAnim;  // 弹出动画
    Lifecycle.State mOldMaxState; // 老的生命周期状态值
    Lifecycle.State mCurrentMaxState; // 当前的生命周期状态值(当前需要改变成那种状态)

    Op(int cmd, Fragment fragment) {
        this.mCmd = cmd;
        this.mFragment = fragment;
        this.mOldMaxState = Lifecycle.State.RESUMED;
        this.mCurrentMaxState = Lifecycle.State.RESUMED;
    }
}

这两个方法比较简单,就是对参数进行判断,然后创建一个 Op 对象(注意创建对象的第一个参数实际就是 OP_ADD),将参数和对象保存进去,然后将整个 Op 对象添加到 FragmentTransaction#mOps 列表中。接下来就看 show()/hide() 方法的调用过程

show()/hide() 方法:

// FragmentTransaction#show() 方法
@NonNull
public FragmentTransaction show(@NonNull Fragment fragment) {
	// 调用 addOp() 方法,传递 OP_SHOW 参数
    addOp(new Op(OP_SHOW, fragment));
    return this;
}

// FragmentTransaction#show() 方法
@NonNull
public FragmentTransaction hide(@NonNull Fragment fragment) {
	// 调用 addOp() 方法,传递 OP_HIDE 参数 
    addOp(new Op(OP_HIDE, fragment));
    return this;
}

这里都是直接调用了 addOp() 方法,只是在创建 Op 对象时传递了不同的参数, add() 方法传递的是 OP_ADD,show() 方法传递的是 OP_SHOW, hide() 方法传递的是 OP_HIDE

通过上面我们发现,这几个方法并没有什么实际的操作,仅仅是检查参数和保存数据,那么他们真正的操作应该就是在 FragmentTransaction#commit() 方法上了,这个方法我们之后在看,因为 add()show()hide() 方法都是保存数据,那我们先来看看 replace() 方法是不是也是只保存了需要操作的数据了。

replace()

同样,replace() 方法是属于 FragmentTransaction 类,我们看一下具体的代码

@NonNull
public final FragmentTransaction replace(@IdRes int containerViewId,
        @NonNull Class<? extends Fragment> fragmentClass, @Nullable Bundle args) {
    return replace(containerViewId, fragmentClass, args, null);
}

@NonNull
public final FragmentTransaction replace(@IdRes int containerViewId,
        @NonNull Class<? extends Fragment> fragmentClass,
        @Nullable Bundle args, @Nullable String tag) {
    return replace(containerViewId, createFragment(fragmentClass, args), tag);
}

@NonNull
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment) {
    return replace(containerViewId, fragment, null);
}

@NonNull
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
        @Nullable String tag)  {
    doAddOp(containerViewId, fragment, tag, OP_REPLACE);
    return this;
}

同样有多个重载方法,但是多个重载方法最终调用的也是 doAddOp() 方法,与我们上面的猜想一样,只是传递的参数是 OP_REPLACE,与上面的对应也是关系类似。

到了这一步,我们就发现了,add()show()hide() 以及replace()方法都是创建了一个 Op 对象,并保存到 FragmentTransaction#mOps 列表中去,实际操作应该是都是在 FragmentTransaction#commit() 方法中了,我们接着就来看看这个方法。

FragmentTransaction#commit()

commit() 方法有多个类似的,我们这里看看常用的 commit()commitAllowingStateLoss() 两个,其实其他的几个也一样,他们最终调用的方法都是一样的,明白了这两个,其他的也就明白了。需要注意的是,这些方法在 FragmentTransaction 类中是抽象的,具体的实现在
BackStackRecord 类中,通过上面的分析我们也知道了,beginTransaction() 方法获取的就是 BackStackRecord 类对象。

BackStackRecord 类中的这两个方法具体实现如下:

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

@Override
public int commitAllowingStateLoss() {
    return commitInternal(true);
}

都是调用了 commitInternal() 方法,只是参数不一样,一个 false,一个 true,这个参数表示是否允许丢失状态信息,具体的作用我们通过源码继续了解。接着往下继续看 BackStackRecord#commitInternal() 方法

int commitInternal(boolean allowStateLoss) {
	// 防止重复提交
    if (mCommitted) throw new IllegalStateException("commit already called");
	// 省略打印日志代码
	
	// 修改状态,正在提交
    mCommitted = true;

	// 判断是否需要保存到回退栈,调用了 addToBackStack() 方法才会为 true
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex();
    } else {
        mIndex = -1;
    }
	// 将操作放入到队列中,调用的是 FragmentManager 类中的方法
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

FragmentManager#enqueueAction() 方法:

void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
	// 是否允许丢失状态,如果不允许,就需要对状态进行检查,检查不通过抛出异常
    if (!allowStateLoss) {
        if (mHost == null) {
            if (mDestroyed) {
                throw new IllegalStateException("FragmentManager has been destroyed");
            } else {
                throw new IllegalStateException("FragmentManager has not been attached to a "
                        + "host.");
            }
        }
        checkStateLoss();
    }
    synchronized (mPendingActions) {
		// mHost 是在 FragmentActivity 中创建,然后传递过来的,如果为 null,表示Fragment的容器布局对应的页面不存在了
        if (mHost == null) {
            if (allowStateLoss) {
                // This FragmentManager isn't attached, so drop the entire transaction.
                return;
            }
            throw new IllegalStateException("Activity has been destroyed");
        }
		// 把操作添加到 mPendingActions 中
        mPendingActions.add(action);
		// 继续调用方法
        scheduleCommit();
    }
}

FragmentManager#scheduleCommit() 方法:

 void scheduleCommit() {
    synchronized (mPendingActions) {
        boolean postponeReady =
                mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        boolean pendingReady = mPendingActions.size() == 1;
		// 判断是否有已经准备好的,需要执行的任务
        if (postponeReady || pendingReady) {
			// 先移除已有的消息,然后再通过Handler发送消息开始处理
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
			// 更新返回状态是否启用,根据回退栈中的Fragment类确定
            updateOnBackPressedCallbackEnabled();
        }
    }
}

主要来看FragmentManager#Handler 需要执行的任务 mExecCommit 做了什么

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

boolean execPendingActions(boolean allowStateLoss) {
	// 执行之前已推迟但现在已准备就绪的事务
    ensureExecReady(allowStateLoss);

    boolean didSomething = false;
	// 1. 根据事务对象生成待执行的操作,并添加到记录中
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
			// 2. 移除多余的操作并执行
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
        } finally {
			// 清空缓存队列数据
            cleanupExec();
        }
        didSomething = true;
    }

    updateOnBackPressedCallbackEnabled();
    doPendingDeferredStart();
    mFragmentStore.burpActive();

    return didSomething;
}

我们一个一个方法来看:

  1. 首先看一下 FragmentManager#generateOpsForPendingActions() 方法

     // FragmentManager#generateOpsForPendingActions()
     private boolean generateOpsForPendingActions(@NonNull ArrayList<BackStackRecord> records,
             @NonNull ArrayList<Boolean> isPop) {
         boolean didSomething = false;
         synchronized (mPendingActions) {
             if (mPendingActions.isEmpty()) {
                 return false;
             }
    
             final int numActions = mPendingActions.size();
             for (int i = 0; i < numActions; i++) {
                 didSomething |= mPendingActions.get(i).generateOps(records, isPop);
             }
     		// 清空 mPendingActions 列表
             mPendingActions.clear();
             mHost.getHandler().removeCallbacks(mExecCommit);
         }
         return didSomething;
     }
    

    在这个方法中遍历 mPendingActions 调用元素(其中的元素是在 FragmentManager#enqueueAction() 方法中添加的 BackStackRecord 对象)的 generateOps() 方法,我们看一下这个方法:

     // BackStackRecord#generateOps() 方法
     @Override
     public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
             @NonNull ArrayList<Boolean> isRecordPop) {
    
         records.add(this);
         isRecordPop.add(false);
         if (mAddToBackStack) {
             mManager.addBackStackState(this);
         }
         return true;
     }
    

    将当前对象加入到 records 中,实际上也就是 FragmentManager#mTmpRecords 列表,并且给FragmentManager#mTmpIsPop 增加了false 元素,最后还根据是否需要加入到回退栈进行处理了。

    generateOpsForPendingActions() 中,执行完 generateOps() 方法后就清空了 FragmentManager#mPendingActions 列表。这个方法到这里就差不多了。我们回头接着看另外一个方法。

  2. 查看另一个 FragmentManager#removeRedundantOperationsAndExecute() 方法:

     // FragmentManager#removeRedundantOperationsAndExecute()
     private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
             @NonNull ArrayList<Boolean> isRecordPop) {
         // ... 
         if (startIndex != numRecords) {
             executeOpsTogether(records, isRecordPop, startIndex, numRecords);
         }
     }
    

    接着看 FragmentManager#executeOpsTogether() 方法:

     // FragmentManager#executeOpsTogether()
     private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
         @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
         final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
         boolean addToBackStack = false;
         if (mTmpAddedFragments == null) {
             mTmpAddedFragments = new ArrayList<>();
         } else {
             mTmpAddedFragments.clear();
         }
         mTmpAddedFragments.addAll(mFragmentStore.getFragments());
         Fragment oldPrimaryNav = getPrimaryNavigationFragment();
         for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
             final BackStackRecord record = records.get(recordNum);
             final boolean isPop = isRecordPop.get(recordNum);
             if (!isPop) {
     			// 1. 不是出栈,走这里
                 oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
             } else {
                 oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
             }
             addToBackStack = addToBackStack || record.mAddToBackStack;
         }
         mTmpAddedFragments.clear();
    
         // ...
     	// 2. 展开操作
         executeOps(records, isRecordPop, startIndex, endIndex);
    
         // ...
     	// 根据是否加入回退栈进行处理
         if (addToBackStack) {
             reportBackStackChanged();
         }
     }
    

    这里把不是特别重要的代码去掉了,主要注意两步:

    1. record.expandOps(mTmpAddedFragments, oldPrimaryNav):这一步主要是操作展开(第二个参数与AndroidX导航组件相关,这里不管他)。比如说一个replace操作,需要把之前的Fragment的移除掉和添加新的Fragment的操作,并把新的操作对象Op添加到mOps列表中,这个列表我们在上面也看到过,不管是add还是replace都会调用 FragmentTransaction#addOp() 方法将一个 Op 对象添加到 mOps。看一下 OP_REPLACE 操作的代码

       case OP_REPLACE: {
           final Fragment f = op.mFragment;
           final int containerId = f.mContainerId;
           boolean alreadyAdded = false;
           for (int i = added.size() - 1; i >= 0; i--) {
               final Fragment old = added.get(i);
               if (old.mContainerId == containerId) {
                   if (old == f) {
                       alreadyAdded = true;
                   } else {
       				// 先移除老的Fragment操作,构建 Op 对象,保存到 mOps 列表
                       final Op removeOp = new Op(OP_REMOVE, old);
                       removeOp.mEnterAnim = op.mEnterAnim;
                       removeOp.mPopEnterAnim = op.mPopEnterAnim;
                       removeOp.mExitAnim = op.mExitAnim;
                       removeOp.mPopExitAnim = op.mPopExitAnim;
                       mOps.add(opNum, removeOp);
                       added.remove(old);
                       opNum++;
                   }
               }
           }
           if (alreadyAdded) {
       		// 如果已经存在,多余操作,删除
               mOps.remove(opNum);
               opNum--;
           } else {
       		// 没有,将操作改为 OP_ADD
               op.mCmd = OP_ADD;
               added.add(f);
           }
       }
      

      对于replace操作,先是判断了是否已经存在(防止重复添加,如果是重复添加,这一步就是多余的,直接移除此次操作);如果不存在,将先将需要被替换的 Fragment 移除掉(也是构建一个 Op 对象,指定 OP_REMOVE (移除)操作),然后将新的 Fragment 操作由 OP_REPLACE 修改为 OP_ADD:新增。

    2. 接下来看一下另一个 FragmentManager#executeOps(records, isRecordPop, startIndex, endIndex) 方法

       FragmentManager#executeOps(records, isRecordPop, startIndex, endIndex)
       private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
       @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
           for (int i = startIndex; i < endIndex; i++) {
               final BackStackRecord record = records.get(i);
               final boolean isPop = isRecordPop.get(i);
               if (isPop) {
                   record.bumpBackStackNesting(-1);
                   boolean moveToState = i == (endIndex - 1);
                   record.executePopOps(moveToState);
               } else {
                   record.bumpBackStackNesting(1);
       			// 不是出栈操作,走else到这里
                   record.executeOps();
               }
           }
       }
      

      继续查看 BackStackRecord#expandOps() 方法:

       void executeOps() {
           final int numOps = mOps.size();
       	// 遍历操作列表,进行操作
           for (int opNum = 0; opNum < numOps; opNum++) {
               final Op op = mOps.get(opNum);
               final Fragment f = op.mFragment;
               if (f != null) {
                   f.setPopDirection(false);
                   f.setNextTransition(mTransition);
                   f.setSharedElementNames(mSharedElementSourceNames, mSharedElementTargetNames);
               }
       		// 1. 根据操作类型进行对应操作,我们主要看 OP_ADD,因为不管是 add 还是 replace 都是走的这一步,其他的操作我们就不一个一个看了。
               switch (op.mCmd) {
                   case OP_ADD:
                       f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                       mManager.setExitAnimationOrder(f, false);
                       mManager.addFragment(f);
                       break;
                   case OP_REMOVE:
                       f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                       mManager.removeFragment(f);
                       break;
                   case OP_HIDE:
                       f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                       mManager.hideFragment(f);
                       break;
                   case OP_SHOW:
                       f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                       mManager.setExitAnimationOrder(f, false);
                       mManager.showFragment(f);
                       break;
                   case OP_DETACH:
                       f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                       mManager.detachFragment(f);
                       break;
                   case OP_ATTACH:
                       f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                       mManager.setExitAnimationOrder(f, false);
                       mManager.attachFragment(f);
                       break;
                   case OP_SET_PRIMARY_NAV:
                       mManager.setPrimaryNavigationFragment(f);
                       break;
                   case OP_UNSET_PRIMARY_NAV:
                       mManager.setPrimaryNavigationFragment(null);
                       break;
                   case OP_SET_MAX_LIFECYCLE:
                       mManager.setMaxLifecycle(f, op.mCurrentMaxState);
                       break;
                   default:
                       throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
               }
      
       		// 2. 如果不是add操作,就会走这里
               if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
                   if (!FragmentManager.USE_STATE_MANAGER) {
                       mManager.moveFragmentToExpectedState(f);
                   }
               }
           }
       	// 3. 最终都会走到这里来
           if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) {
               // Added fragments are added at the end to comply with prior behavior.
               mManager.moveToState(mManager.mCurState, true);
           }
       }
      

    这个方法可以分为三步:
    1. 遍历mOps操作列表,根据操作类型进行对应操作
    2. 如果不是add操作,就调用 FragmentManager.moveFragmentToExpectedState(f)
    3. 调用 FragmentManager.moveToState(int newState, boolean always)

  • 我们一步一步看,首先第一步,case 中调用 FragmentManager#addFragment() 方法

      case OP_ADD:
          f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
          mManager.setExitAnimationOrder(f, false);
          mManager.addFragment(f);
          break;
    

    接着往下走 FragmentManager#addFragment() 方法

      FragmentStateManager addFragment(@NonNull Fragment fragment) {
          if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add: " + fragment);
          FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
          fragment.mFragmentManager = this;
      	// 调用 FragmentStore#makeActive() 方法,将 Fragment 添加到 mActive 中
          mFragmentStore.makeActive(fragmentStateManager);
          if (!fragment.mDetached) {
      		// 调用 FragmentStore#addFragment() 方法,将 Fragment 添加到 mAdded 中
              mFragmentStore.addFragment(fragment);
              fragment.mRemoving = false;
              if (fragment.mView == null) {
                  fragment.mHiddenChanged = false;
              }
              if (isMenuAvailable(fragment)) {
                  mNeedMenuInvalidate = true;
              }
          }
          return fragmentStateManager;
      }
    

    这个方法主要就是将该Fragment添加到mAdded中和mActive中,具体代码比较简单,就不放出来了。

  • 第二步主要是将 mOps 中的所有对应的 Fragment 设置到对应的状态,并且调用回调,这个第二步调用的方法在后面第三步中也会调用到,就在后面放一起说明。

  • 接着我们跳过第二步,直接看第三步调用 FragmentManager.moveToState(int newState, boolean always) 方法

      void moveToState(int newState, boolean always) {
          if (mHost == null && newState != Fragment.INITIALIZING) {
              throw new IllegalStateException("No activity");
          }
      	// always:表示是否需要强制更新状态,即使状态一样,否则的话,状态一样时不更新
          if (!always && newState == mCurState) {
              return;
          }
    
          mCurState = newState;
    
          if (USE_STATE_MANAGER) {
      		// 使用状态管理,(不管是否使用状态管理,最后都是调用的同样的方法,只是在中间过程有些不一样)
              mFragmentStore.moveToExpectedState();
          } else {
      		// 不使用状态管理,在之前,我们已经将相关操作添加到这两个列表中了
      		// mFragmentStore.getFragments() 方法返回的就是 mAdded 列表
              for (Fragment f : mFragmentStore.getFragments()) {
                  moveFragmentToExpectedState(f);
              }
    
      		// mFragmentStore.getActiveFragmentStateManagers() 方法返回的就是 mActive 列表
              for (FragmentStateManager fragmentStateManager :
                      mFragmentStore.getActiveFragmentStateManagers()) {
                  Fragment f = fragmentStateManager.getFragment();
                  if (!f.mIsNewlyAdded) {
                      moveFragmentToExpectedState(f);
                  }
                  boolean beingRemoved = f.mRemoving && !f.isInBackStack();
                  if (beingRemoved) {
                      mFragmentStore.makeInactive(fragmentStateManager);
                  }
              }
          }
    
          startPendingDeferredFragments();
    
          if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
              mHost.onSupportInvalidateOptionsMenu();
              mNeedMenuInvalidate = false;
          }
      }
    

我们分别看一下这两个的调用过程

  • 使用状态管理:直接调用 FragmentStateManager#moveToExpectedState() 方法

      // FragmentStateManager#moveToExpectedState()
       void moveToExpectedState() {
          try {
              mMovingToState = true;
    
              int newState;
      		// 根据状态调用对应的方法  attach()/create()/createView()/...
              while ((newState = computeExpectedState()) != mFragment.mState) {
                  if (newState > mFragment.mState) {
                      // Moving upward
                      int nextStep = mFragment.mState + 1;
                      switch (nextStep) {
                          case Fragment.ATTACHED:
                              attach();
                              break;
                          case Fragment.CREATED:
                              create();
                              break;
                          case Fragment.VIEW_CREATED:
                              ensureInflatedView();
                              createView();
                              break;
                          case Fragment.AWAITING_EXIT_EFFECTS:
                              activityCreated();
                              break;
                          case Fragment.ACTIVITY_CREATED:
                              if (mFragment.mView != null && mFragment.mContainer != null) {
                                  SpecialEffectsController controller = SpecialEffectsController
                                          .getOrCreateController(mFragment.mContainer,
                                                  mFragment.getParentFragmentManager());
                                  int visibility = mFragment.mView.getVisibility();
                                  SpecialEffectsController.Operation.State finalState =
                                          SpecialEffectsController.Operation.State.from(visibility);
                                  controller.enqueueAdd(finalState, this);
                              }
                              mFragment.mState = Fragment.ACTIVITY_CREATED;
                              break;
                          case Fragment.STARTED:
                              start();
                              break;
                          case Fragment.AWAITING_ENTER_EFFECTS:
                              mFragment.mState = Fragment.AWAITING_ENTER_EFFECTS;
                              break;
                          case Fragment.RESUMED:
                              resume();
                              break;
                      }
                  } else {
                      // Moving downward
                      int nextStep = mFragment.mState - 1;
                      switch (nextStep) {
                          case Fragment.AWAITING_ENTER_EFFECTS:
                              pause();
                              break;
                          case Fragment.STARTED:
                              mFragment.mState = Fragment.STARTED;
                              break;
                          case Fragment.ACTIVITY_CREATED:
                              stop();
                              break;
                          case Fragment.AWAITING_EXIT_EFFECTS:
                              if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                                  Log.d(TAG, "movefrom ACTIVITY_CREATED: " + mFragment);
                              }
                              if (mFragment.mView != null) {
                                  // Need to save the current view state if not done already
                                  // by saveInstanceState()
                                  if (mFragment.mSavedViewState == null) {
                                      saveViewState();
                                  }
                              }
                              if (mFragment.mView != null && mFragment.mContainer != null) {
                                  SpecialEffectsController controller = SpecialEffectsController
                                          .getOrCreateController(mFragment.mContainer,
                                                  mFragment.getParentFragmentManager());
                                  controller.enqueueRemove(this);
                              }
                              mFragment.mState = Fragment.AWAITING_EXIT_EFFECTS;
                              break;
                          case Fragment.VIEW_CREATED:
                              mFragment.mInLayout = false;
                              mFragment.mState = Fragment.VIEW_CREATED;
                              break;
                          case Fragment.CREATED:
                              destroyFragmentView();
                              mFragment.mState = Fragment.CREATED;
                              break;
                          case Fragment.ATTACHED:
                              destroy();
                              break;
                          case Fragment.INITIALIZING:
                              detach();
                              break;
                      }
                  }
              }
      		// 根据需要回调 Fragment#onHiddenChanged() 方法
              if (FragmentManager.USE_STATE_MANAGER && mFragment.mHiddenChanged) {
                  if (mFragment.mView != null && mFragment.mContainer != null) {
                      // Get the controller and enqueue the show/hide
                      SpecialEffectsController controller = SpecialEffectsController
                              .getOrCreateController(mFragment.mContainer,
                                      mFragment.getParentFragmentManager());
                      if (mFragment.mHidden) {
                          controller.enqueueHide(this);
                      } else {
                          controller.enqueueShow(this);
                      }
                  }
                  if (mFragment.mFragmentManager != null) {
                      mFragment.mFragmentManager.invalidateMenuForFragment(mFragment);
                  }
                  mFragment.mHiddenChanged = false;
                  mFragment.onHiddenChanged(mFragment.mHidden);
              }
          } finally {
              mMovingToState = false;
          }
      }
    
  • 不使用状态管理:FragmentManager#moveFragmentToExpectedState(f)(这个方法也就是上面非add操作时先会调用的方法,这里就一起看了) -> FragmentManager#moveToState(@NonNull Fragment f) -> FragmentManager#moveToState(@NonNull Fragment f, int newState) -> FragmentManager#moveToState(@NonNull Fragment f, int newState) -> 根据状态调用 FragmentStateManager#attach()/create()/createView()/activityCreated()/.../destroy()/detach() 等方法,和使用状态管理调用同样的方法。

最后,通过调用FragmentStateManager#attach()/create()/createView()/activityCreated()/.../destroy()/detach() 等方法最终会回调 Fragment 的对应生命周期方法。

FragmentView 加载到容器中的过程

Fragment#createView() 方法的 View 加载到具体的页面上在 FragmentStateManager#createView() 方法中实现:

  1. 在该方法(FragmentStateManager#createView())中调用 Fragment#performCreateView() 方法进而调用 Fragment#onCreateView() 方法创建View 并赋值给 Fragment 的成员变量 mView

  2. 在该方法(FragmentStateManager#createView())中接着调用 FragmentStateManager#addViewToContainer() 方法

     void addViewToContainer() {
         int index = mFragmentStore.findFragmentIndexInContainer(mFragment);
         mFragment.mContainer.addView(mFragment.mView, index);
     }
    

    通过调用 addView() 方法将 View 增加到容器中,mContainer 就是加载 Fragment 的容器。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-08 08:15:26  更:2022-05-08 08:16:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 0:21:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码