概述
平时开发中经常使用Fragment的场景是创建Fragment并添加到FragmentActivity的指定布局容器中。要实现这样的操作,首先需要获取FragmentManager,接着开启事务FragmentTransaction,并添加add、remove、replace、hide、show等等操作,最后commitXXX提交事务执行对应操作。
接下来进入源码追踪这个过程,看看FragmentManager是如何进行调度执行。
源码探究
文中源码基于’androidx.fragment:fragment:1.1.0’
FragmentManager的由来
在FragmentActivity中通过getSupportFragmentManager方法来获取FragmentManager:
[FragmentActivity.java]
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
该方法中又通过mFragments成员来获取:
[FragmentController.java]
public FragmentManager getSupportFragmentManager() {
return mHost.mFragmentManager;
}
其中又通过mHost成员来获取。
在研究FragmentManager之前,先来看看mFragments、mHost是什么。
FragmentController
先来看看FragmentActivity的mFragments成员:
[FragmentActivity.java]
public class FragmentActivity extends ComponentActivity implements
ActivityCompat.OnRequestPermissionsResultCallback,
ActivityCompat.RequestPermissionsRequestCodeValidator {
// ···
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
// ···
}
mFragments为FragmentController对象。
接着看createController方法,这里传入HostCallbacks实例:
[FragmentController.java]
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
}
private FragmentController(FragmentHostCallback<?> callbacks) {
// 持有HostCallbacks引用
mHost = callbacks;
}
HostCallbacks
在创建FragmentController时,实例化了HostCallbacks并赋值给FragmentController的mHost成员。
[FragmentActivity.java]
class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
ViewModelStoreOwner,
OnBackPressedDispatcherOwner {
public HostCallbacks() {
super(FragmentActivity.this /*fragmentActivity*/);
}
// ···
}
HostCallbacks继承自FragmentHostCallback,为FragmentActivity的内部类,持有FragmentActivity的引用。
[FragmentHostCallback.java]
public abstract class FragmentHostCallback<E> extends FragmentContainer {
// ···
FragmentHostCallback(@NonNull FragmentActivity activity) {
this(activity, activity /*context*/, new Handler(), 0 /*windowAnimations*/);
}
FragmentHostCallback(@Nullable Activity activity, @NonNull Context context,
@NonNull Handler handler, int windowAnimations) {
// 持有FragmentActivity上下文引用
mActivity = activity;
mContext = Preconditions.checkNotNull(context, "context == null");
// 构造函数中创建的Handler,默认运行在主线程
mHandler = Preconditions.checkNotNull(handler, "handler == null");
// 动画相关,默认为0
mWindowAnimations = windowAnimations;
}
// ···
}
可以看出HostCallbacks持有当前FragmentActivity上下文,并创建了一个主线程Handler。
FragmentManagerImpl
FragmentManager为抽象类,而FragmentManagerImpl是其实现类:
[FragmentManagerImpl.java]
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
// ···
}
在FragmentHostCallback实例化时会创建FragmentManagerImpl:
[FragmentHostCallback.java]
public abstract class FragmentHostCallback<E> extends FragmentContainer {
// ···
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
// ···
}
FragmentHostCallback的mFragmentManager成员持有FragmentManagerImpl。
FragmentManagerImpl的绑定
在FragmentActivity的onCreate方法中:
[FragmentActivity.java]
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 调用FragmentController的attachHost方法,参数传null
mFragments.attachHost(null /*parent*/);
// ···
}
接着看attachHost方法:
[FragmentController.java]
public void attachHost(@Nullable Fragment parent) {
// 调用FragmentManagerImpl的attachController方法,并传入HostCallbacks实例,参数parent为null。
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
进入FragmentManagerImpl的attachController方法:
[FragmentManagerImpl.java]
public void attachController(@NonNull FragmentHostCallback host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
// 持有HostCallbacks引用
mHost = host;
mContainer = container;
mParent = parent;
if (mParent != null) {
// Since the callback depends on us being the primary navigation fragment,
// update our callback now that we have a parent so that we have the correct
// state by default
updateOnBackPressedCallbackEnabled();
}
// Set up the OnBackPressedCallback
// 省略BackPressed设置部分
// ···
// Get the FragmentManagerViewModel
// 省略ViewModel设置部分
// ···
}
FragmentActivity在onCreate中进行FragmentManagerImpl的绑定操作,在FragmentManagerImpl的attachController方法中接收HostCallbacks实例并保存。
FragmentController、HostCallbacks、FragmentManagerImpl之间关系
FragmentActivity持有FragmentController引用,FragmentController持有HostCallbacks引用,HostCallbacks持有FragmentActivity引用,FragmentActivity和FragmentManagerImpl互相持有引用。
FragmentActivity通过FragmentController获取HostCallbacks,再通过HostCallbacks间接调用FragmentManagerImpl。FragmentManagerImpl通过HostCallbacks来间接获取上下文和执行回调方法。
添加事务操作
开启事务
获取到FragmentManagerImpl实例后,通过它的beginTransaction方法开启一个事务:
[FragmentManagerImpl.java]
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
这里创建BackStackRecord(继承自FragmentTransaction,并实现BackStackEntry、OpGenerator接口),BackStackRecord将持有FragmentManagerImpl。
FragmentTransaction封装一个事务,一个事务包含一组操作(单个或多个操作)。
添加add Fragment的操作
这里以,往FragmentActivity中添加一个Fragment为例。
通常添加Fragment是通过调用FragmentTransaction的add方法,传入布局ID和Fragment实例:
[FragmentTransaction.java]
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag) {
// tag可选参数,可通过tag查找fragment,OP_ADD标识add操作类型
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
BackStackRecord重写了doAddOp方法:
[BackStackRecord.java]
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
super.doAddOp(containerViewId, fragment, tag, opcmd);
// 将持有的FragmentManagerImpl赋值给Fragment的mFragmentManager成员
fragment.mFragmentManager = mManager;
}
该方法中通过super还是调用FragmentTransaction的doAddOp,只是在执行完后为Fragment的mFragmentManager成员赋值。
[FragmentTransaction.java]
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
final Class<?> fragmentClass = fragment.getClass();
final int modifiers = fragmentClass.getModifiers();
// 检查fragment是否是匿名类,或者非public访问性,或者定义在另一个类中但没有声明static
if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
|| (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
+ " must be a public static class to be properly recreated from"
+ " instance state.");
}
if (tag != null) {
// 检查是否fragment已有tag但和当前传入的tag不同
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment "
+ fragment + ": was " + fragment.mTag
+ " now " + tag);
}
// fragment保存tag
fragment.mTag = tag;
}
// containerViewId即为FragmentActivity中用于添加这个fragment的布局容器ID
if (containerViewId != 0) {
if (containerViewId == View.NO_ID) {
throw new IllegalArgumentException("Can't add fragment "
+ fragment + " with tag " + tag + " to container view with no id");
}
// 检查是否fragment已经设置容器ID但与当前传入的ID不同
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
// fragment保存容器ID,mFragmentId默认为容器ID
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
// 添加操作
addOp(new Op(opcmd, fragment));
}
该方法中做了以下几步:
- 该方法中首先校验我们自定义的Fragment:
- 不能是匿名类
- 访问性必须是public
- 若是成员类,必须是静态类
- 接着检查tag(若有传入)是否和fragment已有保存的不同,最后保存在fragment中
- 接着检查布局ID(若有传入),该布局为FragmentActivity中用于承载fragment的ViewGroup,必须有设置ID,fragment中若已有设置必须相同,最后fragment保存容器ID,mFragmentId默认也为容器ID
- 封装Op保存操作类型和fragment,并添加至操作集合
Op
Op表示一个操作,看它的构造函数:
[FragmentTransaction.java]
Op(int cmd, Fragment fragment) {
// 保存操作类型
this.mCmd = cmd;
// 保存待操作的fragment
this.mFragment = fragment;
// 生命周期状态置为RESUMED,对应Activity执行onResume之后的状态
this.mOldMaxState = Lifecycle.State.RESUMED;
this.mCurrentMaxState = Lifecycle.State.RESUMED;
}
addOp
[FragmentTransaction.java]
void addOp(Op op) {
// 保存Op对象
mOps.add(op);
// 动画相关,默认都为0
op.mEnterAnim = mEnterAnim;
op.mExitAnim = mExitAnim;
op.mPopEnterAnim = mPopEnterAnim;
op.mPopExitAnim = mPopExitAnim;
}
FragmentTransaction的mOps成员用于保存Op对象,mOps为ArrayList。
提交事务
FragmentTransaction有四个提交事务的方法:commit、commitAllowingStateLoss、commitNow、commitNowAllowingStateLoss。这四个方法都为抽象类,具体实现在BackStackRecord中。
这里以commitAllowingStateLoss为例:
[BackStackRecord.java]
public int commitAllowingStateLoss() {
return commitInternal(true);
}
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
// 省略DEBUG部分 ···
mCommitted = true;
// mAddToBackStack默认为false,若调用addToBackStack方法的话为true
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
// 此时传入的allowStateLoss为true
// 通过FragmentManagerImpl入队
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
接着看FragmentManagerImpl的enqueueAction方法,此时传入BackStackRecord自身和true:
[FragmentManagerImpl.java]
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
if (allowStateLoss) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
// mPendingActions表示待执行操作集合,action即为BackStackRecord(实现了OpGenerator接口)
mPendingActions.add(action);
scheduleCommit();
}
}
接着看scheduleCommit方法:
[FragmentManagerImpl.java]
void scheduleCommit() {
synchronized (this) {
// 标记是否存在延迟事务,默认不存在
boolean postponeReady =
mPostponedTransactions != null && !</