- Activity 是如何与 Fragment 关联,如何操作 fragment 的?
- Fragment 的本质是一个 View 吗?
前言
Activity 和 Fragment 密不可分, 分析 Fragment 必须去从 Activity 的生命周期着手去分析其中和 Fragment 的关联。
我们在 Activity 操作 Fragment 通过如下代码:
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container, new MyFragment())
.commit();
复制代码
查看源码可以发现 getSupportFragmentManager()
内部通过 FragmentController
操作。
这个 FragmentController
类是负责控制 Fragment 的。
它的内部持有一个 FragmentHostCallback
,所有的核心操作都间接交给了这个类,这个 FragmentHostCallback
类才是重点。而且它的命名是 mHost
,它才是最主要的操作者。FragmentController
只是个中间对象。
// Fragment 可以寄生在任何对象上,让 fragment 寄存在自己身上需要实现 FragmentHostCallback 类,实现里面的一些方法 。
public abstract class FragmentHostCallback<E> extends FragmentContainer
复制代码
Activity 通过 FragmentController
类管理 Fragment。FragmentController
的实例在成员变量中实例化,所以当 Activity
被实例化的时候,FragmentController
就被实例化了。
public class FragmentActivity {
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
// ...
}
复制代码
那么 Activity
在哪里被实例化的?
Activit 的实例化
实例 Activity 的过程发生在 ActivityThread
中的 performLaunchActivity()
中的这段代码。
// 通过 Instrumentation 的 newActivity 方法使用类加载器创建 Activity 对象
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
activity.attach();
/**-------------------------------------------------------*/
// newActivity() 方法内部调用了 Activity 的无参实例:
Activity activity = (Activity)clazz.newInstance();
复制代码
在 Activity 实例化之后会立刻调用 Activity#attach(),这个方法内部会调用mFragments.attachHost(null /*parent*/);
public void attachHost(Fragment parent) {
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
复制代码
// 第一个参数是宿主;
// 第二参数是容器,FragmentHostCallback 继承于 FragmentContainer 也代表容器;
// 第三个参数是父类 Fragment
public void attachController(FragmentHostCallback host,
FragmentContainer container, Fragment parent) {
// 宿主只能有一个
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
}
复制代码
这个方法最终将宿主对象和控制器中的 FragmentManager 关联,内部就是进行赋值。
为什么里面传的是 null?注释写了 parent。应该是传入的父类 fragment,而由 Activity 创建的 fragment 没有父类,所以是 null。
FragmentController 的初始化
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
复制代码
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
复制代码
createController()
方法中传入了一个 HostCallbacks
实例。
HostCallbacks
是 FragmentActivity
的内部类,是 FragmentHostCallback
的实现类。
HostCallbacks 的初始化
在构造函数中调用父类的构造函数,将当前的 Activity
实例传进去:
public HostCallbacks() {
super(FragmentActivity.this /*fragmentActivity*/);
}
复制代码
父类 FragmentHostCallback
有 3 个构造方法:
public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
this(context instanceof Activity ? (Activity) context : null, context, handler, windowAnimations);
}
FragmentHostCallback(FragmentActivity activity) {
this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
}
FragmentHostCallback(Activity activity, Context context, Handler handler,
int windowAnimations) {
mActivity = activity;
mContext = context;
mHandler = handler;
mWindowAnimations = windowAnimations;
}
复制代码
HostCallbacks
调用的是第二个构造,将 mActivity
、mContext
赋值为 Activity
的实例,mHandler
赋值为 Activity
中的 mHandler
,mWindowAnimations
直接赋值 0。
这里的 mHandler
也是在 Activty
被实例化的时候实例化,看代码是处理 Fragment
的 stop
和 resume
状态的。具体怎么处理的后面再看,这里先了解传入的 mHandler 在哪里初始化的。
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REALLY_STOPPED:
if (mStopped) {
doReallyStop(false);
}
break;
case MSG_RESUME_PENDING:
onResumeFragments();
mFragments.execPendingActions();
break;
default:
super.handleMessage(msg);
}
}
};
复制代码
FragmentHostCallback 的成员变量
// Actvity
private final Activity mActivity;
// 上下文
final Context mContext;
// 在 Activity 中实例化的 handler,负责处理 fragment 的生命周期,内部执行具体的事务
private final Handler mHandler;
// window 的动画
final int mWindowAnimations;
// 在成员变量中直接实例化了 FragmentManagerImpl
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
// loaderManager 的集合, loadMangaer 通过 Fragment#getLoaderManager() 获取,最终是由 FragmentHostCallback#getLoaderManager() 获取。
/** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers;
// 标记 fragmentLoader 是否应该保存 fragment 的状态
/** Whether or not fragment loaders should retain their state */
private boolean mRetainLoaders;
// fragment 宿主的 loaderManager,通过 Activity#getLoaderManager() 获取, 最终是由 FragmentHostCallback#getLoaderManagerImpl() 获取。
/** The loader manger for the fragment host [i.e. Activity#getLoaderManager()] */
private LoaderManagerImpl mLoaderManager;
// 检查 loaderManager 是否为空
private boolean mCheckedForLoaderManager;
// 宿主的 loaderManager 是否开始加载
/** Whether or not the fragment host loader manager was started */
private boolean mLoadersStarted;
复制代码
根据注释和局部代码初步了解一下这些变量的含义,有个大概的印象。可以看到内部有一个 loader manager 的存在。宿主有一个单独的加载器,以 "(root)"
为键存入了 SimpleArrayMap<String, LoaderManager>
集合中。 每个 fragment
也对应有一个自己的 loader manager。 这个 load manager 是干啥的,现在还不知道,后面再看。
FragmentManagerImpl 的初始化
FragmentManager、FragmentManagerState、FragmentManagerImpl 三个类共存于 FragmentManager.java 文件下,它们是同级的关系,而不是内部类的关系。
我们平常操作 fragment
所调用的 getSupportFragmentManager()
返回的就是 FragmentManager
对象。顾名思义,它是 fragment 的管理者,负责添加、删除、替换 fragment 等一些操作。
FragmentManager 是一个抽象类,定义了操作 fragment 的一系列方法,如开启事务、进栈、弹栈等。除此之外,有一个 BackStackEntry
接口和一个 FragmentLifecycleCallbacks
生命周期回调。
public abstract class FragmentManager {
public abstract FragmentTransaction beginTransaction();
public abstract boolean executePendingTransactions();
public abstract Fragment findFragmentById(@IdRes int id);
public abstract Fragment findFragmentByTag(String tag);
public abstract void popBackStack();
public abstract boolean popBackStackImmediate();
// .....
// 当调用 FragmentTransaction#addToBackStack(String) 时,将放入回退栈的 frament 的信息存起来。用于以后检索。
public interface BackStackEntry {
public int getId();
public String getName();
@StringRes public int getBreadCrumbTitleRes();
@StringRes public int getBreadCrumbShortTitleRes();
public CharSequence getBreadCrumbTitle();
public CharSequence getBreadCrumbShortTitle();
}
// 回退栈内容改变时的监听接口
public interface OnBackStackChangedListener {
public void onBackStackChanged();
}
// frgment 的生命周期回调
public abstract static class FragmentLifecycleCallbacks {
public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {
}
public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {
}
public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
}
public void onFragmentActivityCreated(FragmentManager fm, Fragment f,
Bundle savedInstanceState) {
}
public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,
Bundle savedInstanceState) {
}
// ...
}
}
复制代码
FragmentManager
的具体实现是 FragmentManagerImpl
具体内部的实现,现在先不深入看了。现在先把主要的流程走通,后面再看具体的细节。
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
复制代码
FragmentMangerImpl 在 FragmentHostCallback() 的成员变量中被实例化。所以 Activity 被实例化的时候,FragmentController
、HostCallbacks
、FragmentManagerImpl
都会被实例化。然后再通过我们前面说到的 attach()
将他们关联,让 FragmentManagerImpl
实例持有 HostCallbacks
实例。
Activity 的 onCreate()
Activity 的生命周期从 onCreate 开始, 在 Activity 实例化后,FragmentManager 就可以被使用来操作 fragment,即我们常用的 getFragmentManager().beginTransaction().add()
等操作。 这些操作都是在 Activity 的 onCreate
完成的。
Activity 的 onCreate()
发生在哪里?
onCreate()
也发生在 ActivityThread 中的 performLaunchActivity()
中:
mInstrumentation.callActivityOnCreate(activity, r.state);
复制代码
// Instrumentation
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
复制代码
// Activity
final void performCreate(Bundle icicle) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
复制代码
protected void onCreate(@Nullable Bundle savedInstanceState) {
// ...
mFragments.dispatchCreate();
}
复制代码
final void performCreateCommon() {
// ...
mFragments.dispatchActivityCreated();
// ...
}
复制代码
最终在 Activity 的 onCreate
调用了 FragmentController#dispatchCreate()
,接着在 performCreateCommon()
中调用了 FragmentController#dispatchActivityCreated()
:
public void dispatchCreate() {
mHost.mFragmentManager.dispatchCreate();
}
public void dispatchActivityCreated() {
mHost.mFragmentManager.dispatchActivityCreated();
}
复制代码
这两个方法都是调用的 HostCallback
实例中的 FragmentManagerImpl
实例的方法。
public void dispatchCreate() {
mStateSaved = false;
mExecutingActions = true;
moveToState(Fragment.CREATED, false);
mExecutingActions = false;
}
public void dispatchActivityCreated() {
mStateSaved = false;
mExecutingActions = true;
moveToState(Fragment.ACTIVITY_CREATED, false);
mExecutingActions = false;
}
复制代码
看到这里结合源码注释我们知道这俩方法通过 moveToState()
去更新 Fragment 的 状态。并且用 mExecutingActions
标记事务是否在进行。 用 mStateSaved
标记状态是否保存了。
void moveToState(int newState, boolean always) {
// 状态没变且没有设置必须更新就结束
if (!always && newState == mCurState) {
return;
}
// 更新当前状态
mCurState = newState;
// ...
}
复制代码
这个方法有 2 个参数,第一个参数是即将更新的状态,第二个参数表示是否更新所有 fragment 的状态。
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.
int mState = INITIALIZING;
复制代码
Fragment 的状态有上面几种。默认是 INITIALIZING。
这里我有个地方有点疑惑:Activity onCreate() 的时候给 FragmentManager 通知更新 CREATED
状态,此时应该还没有创建任何 fragment,为啥是个 CREATED
。看到后面又有个 STOPPED
,表示创建完成,还没开始的状态。那么 CREATED
应该表示的是开始创建,还没创建好。
事务操作
接着我们会在 Activity
中的 onCreate()
创建执行 fragment 的事务。 getFragmentManager()
前面已经看过,现在来看 beginTransaction()
。
// FragmentManagerImpl
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
复制代码
// BackStackState
final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {
static final String TAG = FragmentManagerImpl.TAG;
static final boolean SUPPORTS_TRANSITIONS = Build.VERSION.SDK_INT >= 21;
final FragmentManagerImpl mManager;
// 表示一系列操作
static final int OP_NULL = 0;
static final int OP_ADD = 1;
static final int OP_REPLACE = 2;
static final int OP_REMOVE = 3;
static final int OP_HIDE = 4;
static final int OP_SHOW = 5;
static final int OP_DETACH = 6;
static final int OP_ATTACH = 7;
static final int OP_SET_PRIMARY_NAV = 8;
static final int OP_UNSET_PRIMARY_NAV = 9;
// 双链表的节点
static final class Op {
// 执行的操作(添加/删除。。。)
int cmd;
Fragment fragment;
// 进栈动画
int enterAnim;
int exitAnim;
// 出栈动画
int popEnterAnim;
int popExitAnim;
Op() {
}
Op(int cmd, Fragment fragment) {
this.cmd = cmd;
this.fragment = fragment;
}
}
// ...
}
复制代码
BackStackRecord 继承 FragmentTransation 抽象类,同时实现 BackStackEntry 和 OpGenerator 接口。我们在程序里要进行 add,remove,replace 等等操作时,用的是 FragmentTransation 类型,其实这个实例是 BackStackRecord 对象。
BackStackRecord 是用于保存用户一次提交的操作行为,一次提交并不是一种变化,而是一系列的变化,是一组 add、replace、remove 变化的集合。每一次的变化,即是一次操作,用 Op 类来表示。在 BackStackRecord 里保存了一个双向链表 (mHead, mTail),用于保存一组操作。Op 类中的 cmd 表示操作类型(如 add,replace,remove 等等)
例如:
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container, new MyFragment())
.hide(R.id.container,fragment2)
.replace(R.id.container,fragment3)
.commit();
复制代码
最终通过 commit()
方法提交一些列操作。
BackStackRecord
BackStackRecord 实现了操作 fragment 的所有事务,每个方法内部都是由 doAddOp
实现的。
@Override
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
if (containerViewId == 0) {
throw new IllegalArgumentException("Must use non-zero containerViewId");
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
@Override
public FragmentTransaction remove(Fragment fragment) {
addOp(new Op(OP_REMOVE, fragment));
return this;
}
@Override
public FragmentTransaction hide(Fragment fragment) {
addOp(new Op(OP_HIDE, fragment));
return this;
}
@Override
public FragmentTransaction show(Fragment fragment) {
addOp(new Op(OP_SHOW, fragment));
return this;
}
@Override
public FragmentTransaction detach(Fragment fragment) {
addOp(new Op(OP_DETACH, fragment));
return this;
}
@Override
public FragmentTransaction attach(Fragment fragment) {
addOp(new Op(OP_ATTACH, fragment));
return this;
}
复制代码
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
// ...
// 将 manager 赋值给 fragment
fragment.mFragmentManager = mManager;
// 设置 containerViewId
if (containerViewId != 0) {
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
// ...
// 将这个事务对象加到 ArrayList 中
addOp(new Op(opcmd, fragment));
}
复制代码
提交事务
常用的提交事务, 一种是将所有事物放入事务队列,轮询执行。另一种是立刻执行,从方法命名也可以看出来。看看它们内部是如何提交的。而立刻提交是不允许加入回退栈的。
@Override
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
mCommitted = true;
// 判断是否加入回退栈
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
// 将事务添加到轮询队列等待执行
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
public void enqueueAction(OpGenerator 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<>();
}
mPendingActions.add(action);
scheduleCommit();
}
}
// 将事务交通过 handler post 执行
private void scheduleCommit() {
synchronized (this) {
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
// mExecCommit 这个 Runnable 做的事:
public boolean execPendingActions() {
ensureExecReady(true);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
// 优化执行我们的实务操作,具体的执行就在这个方法里
optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
doPendingDeferredStart();
return didSomething;
}
复制代码
// 这里进行了优化和执行事务的操作,执行事务是由 executeOpsTogether 完成
private void optimizeAndExecuteOps(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop) {
// ...
final int numRecords = records.size();
int startIndex = 0;
// 遍历所有的事务
for (int recordNum = 0; recordNum < numRecords; recordNum++) {
// 标记优化
final boolean canOptimize = records.get(recordNum).mAllowOptimization;
if (!canOptimize) {
// ..
if (startIndex != recordNum) {
executeOpsTogether(records, isRecordPop, startIndex, recordNum);
}
executeOpsTogether(records, isRecordPop, recordNum, optimizeEnd);
// ...
}
}
if (startIndex != numRecords) {
executeOpsTogether(records, isRecordPop, startIndex, numRecords);
}
}
// 这里发现执行事务由 executeOps 方法来执行的
private void executeOpsTogether(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
final boolean allowOptimization = records.get(startIndex).mAllowOptimization;
// ...
// ...
executeOps(records, isRecordPop, startIndex, endIndex);
// ...
if (postponeIndex != startIndex && allowOptimization) {
// need to run something now
FragmentTransition.startTransitions(this, records, isRecordPop, startIndex,
postponeIndex, true);
moveToState(mCurState, true);
}
// ..
if (addToBackStack) {
reportBackStackChanged();
}
}
复制代码
// 最终判断执行 executeOps 还是 executePopOps
private static void executeOps(ArrayList<BackStackRecord> records,
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);
// Only execute the add operations at the end of
// all transactions.
boolean moveToState = i == (endIndex - 1);
record.executePopOps(moveToState);
} else {
record.bumpBackStackNesting(1);
record.executeOps();
}
}
}
复制代码
这里通过 fragmentManager 来操作
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;
if (f != null) {
f.setNextTransition(mTransition, mTransitionStyle);
}
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;
// ...
}
}
// ...
}
复制代码
最后调用 movetToState()
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
makeActive(fragment);
if (!fragment.mDetached) {
// ...
mAdded.add(fragment);
fragment.mAdded = true;
fragment.mRemoving = false;
if (fragment.mView == null) {
fragment.mHiddenChanged = false;
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
if (moveToStateNow) {
moveToState(fragment);
}
}
}
复制代码
这一段的代码特别长,根据状态调用对应的生命周期, 在添加的时候把 View 添加进父布局。通过 View.GONE/VISIBLE
显示隐藏 Fragment。
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
if (f.mState <= newState) {
// ...
switch (f.mState) {
case Fragment.INITIALIZING:
// OnFragmentPreAttached
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
// 调用 fragment 的 onAttach
f.onAttach(mHost.getContext());
// 回调宿主的 onAttachFragment
mHost.onAttachFragment(f);
dispatchOnFragmentAttached(f, mHost.getContext(), false);
// 执行 fragment 的 onCreate
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
// ...
case Fragment.CREATED:
f.mContainer = container;
// fragmenr 执行 onCreateView 创建 View
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (container != null) {
// 加入父布局
container.addView(f.mView);
}
// 设置 View 的 GONE VISIBLE 来控制 hide,show
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
// onViewCreated
f.onViewCreated(f.mView, f.mSavedFragmentState);
// 回调
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,false);
// onActivityCreated
f.performActivityCreated(f.mSavedFragmentState);
// ...
case Fragment.ACTIVITY_CREATED:
//...
case Fragment.STOPPED:
// ..
// onStart
f.performStart();
dispatchOnFragmentStarted(f, false);
case Fragment.STARTED:
// ...
// onResume
f.performResume();
dispatchOnFragmentResumed(f, false);
}
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
// onPause
f.performPause();
dispatchOnFragmentPaused(f, false);
// ..
case Fragment.STARTED:
// onStop
f.performStop();
dispatchOnFragmentStopped(f, false);
// ...
case Fragment.STOPPED:
f.performReallyStop();
// ...
case Fragment.ACTIVITY_CREATED:
// ..
// onDestroyView
f.performDestroyView();
dispatchOnFragmentViewDestroyed(f, false);
case Fragment.CREATED:
// onDestory
f.performDestroy();
// onDetach
f.performDetach();
// ...
}
}
}
复制代码
总结
回到最初疑惑的 2 个问题。
- Activity 是如何与 Fragment 关联,如何操作 fragment 的?
Activiy 通过 FragmentManager 得到事务的实现类 BackStackRecord,它将 Fragment 封装成一个 Ops,提交给 FragmentManager 处理。如果是异步提交,就通过 Handler 发送 Runnable 任务,FragmentManager 拿到任务后,先处理 Ops 状态,然后调用 moveToState() 方法根据状态调用 Fragment 对应的生命周期方法,从而达到 Fragment 的添加、布局的替换隐藏等。
- Fragment 的本质是一个 View 吗?
本质上是一个对 View 的封装,它持有 view, containerView, fragmentManager, childFragmentManager 等信息。