本文章分析了Fragment的管理器FragmentManager、事务FragmentTransaction 、以及完整的声明周期和动态加载Fragment的原理解析。
1、Fragment管理器
FragmentManager 类负责在应用的 fragment 上执行一些操作,如添加、移除或替换操作,以及将操作添加到返回堆栈。
您可以从 activity 或 fragment 访问 FragmentManager。
FragmentActivity 及其子类(如 AppCompatActivity)都可以过 getSupportFragmentManager() 方法访问 FragmentManager。
fragment 可以托管一个或多个子 fragment。在 fragment 内,您可以通过 getChildFragmentManager() 获取对管理 fragment 子级的 FragmentManager 的引用。如果您需要访问其宿主 FragmentManager,可以使用 getParentFragmentManager()。
如需在布局容器中显示 fragment,请使用 FragmentManager 创建 FragmentTransaction。在事务中,您随后可以对容器执行 add() 或 replace() 操作。您可以使用 findFragmentById() 获取对布局容器中当前 fragment 的引用。这些都是我们动态创建并使用fragment的常规操作。
这里说一句哈,FragmentManager是个抽象类因此它的实际工作由子类FragmentManagerImpl帮忙完成。
2、Fragment事务
上面提到了,FragmentManager 可以通过 Fragment 执行添加、移除、替换以及其他操作,以响应用户互动。但实际replace替换、add添加、hide隐藏、show显示、remove移除等方法都不是FragmentManager的而是FragmentTransaction 类提供。您提交的每组 Fragment 都称为一个“事务”,可以使用 FragmentTransaction 类提供的上述 API 指定在事务内需执行何种操作。每个 事务必须执行提交。commit() 调用会向 FragmentManager 发出信号,指明所有操作均已添加到事务中。
您可以将多个操作分组到一个事务中。例如,通过一个事务就可以添加或替换多个 Fragment。当您在同一个屏幕上显示多个同级 Fragment(例如使用分块视图)时,该分组会很实用。您也可将每个事务保存到由 FragmentManager 管理的返回堆栈内,从而让用户能够回退 Fragment 更改(类似于回退 Activity)。
调用 beginTransaction() 从 FragmentManager 获取 FragmentTransaction 实例。
3、生命周期
这是一张来自官网的Fragment生命周期流程图。其实这里少了最初始onAttach() 和 最后的onDetach()回调方法,我们加上他俩一起来看。
每个 Fragment 显示或被销毁都有自己的生命周期。当用户浏览应用并与之互动时,您的 Fragment 会在添加、移除时以及进入或退出屏幕时完成其生命周期内各种状态的转换。下面我们按着一个Fragment展示到被销毁的过程分析13个生命周期:
(1)将 Fragment 添加到 FragmentManager 并附加到其宿主 Activity 后,系统将调用 onAttach() 回调,最早的。
(2)Fragment 的 SavedStateRegistry 恢复与 Fragment 本身关联的所有已保存状态,会调用 onCreate() 回调。此时尚未创建 Fragment 的视图,只有在创建该视图后,才应恢复与该 Fragment 的视图关联的任何状态。
(3)当 Fragment 提供有效的 View 实例时,才会创建 Fragment 的视图 Lifecycle,这会在适当的时间自动膨胀视图。系统将调用 onCreateView()回调。这方法也是我们最常用的回调之一,重写他提供对应的布局view对象创建视图。
(4)当且仅当 Fragment 的视图已使用非 null View 实例化后,该 View 才会在 Fragment 上设置,才能使用 getView() 检索到,系统调用 onViewCreated() 回调。
创建 Fragment 的视图后,系统会恢复之前的视图状态(如有),系统调
(5)用 onViewStateRestored() 回调。如果 Fragment 的视图为非 null,在 Fragment 的 Lifecycle 转为 STARTED 后,Fragment 的视图 Lifecycle 会立即转为 STARTED。当 Fragment 转为 STARTED 时,系统会调用 onStart() 回调。
(6)如果 Fragment 可见,即表示所有 Animator 和 Transition 效果均已完成,且 Fragment 已做好与用户互动的准备。该 Fragment 的 Lifecycle 会转为 RESUMED 状态,并且系统会调用 onResume() 回调。
(7)当用户开始离开 Fragment,但是 Fragment 仍然可见时,Fragment 及其视图的 Lifecycle 会返回 STARTED 状态,并向其观察者发出 ON_PAUSE 事件。系统会调用其 onPause() 回调。
(8)Fragment 不再可见后,Fragment 及其视图的 Lifecycle 将转为 CREATED 状态,并向其观察者发出 ON_STOP 事件。系统会调用其 onStop() 回调。
(9)完成所有退出动画和转换并且 Fragment 的视图与窗口分离之后,Fragment 的视图 Lifecycle 会转为 DESTROYED 状态并向其观察者发出 ON_DESTROY 事件。然后,Fragment 会调用其 onDestroyView() 回调。此时,Fragment 的视图的生命周期结束
(10)如果 Fragment 已被移除,或者 FragmentManager 已被销毁,Fragment 的 Lifecycle 会转为 DESTROYED 状态,并向其观察者发送 ON_DESTROY 事件。然后,Fragment 会调用其 onDestroy() 回调。此时,Fragment 的生命周期结束。
(11)将 Fragment 从 FragmentManager 中移除并将其与其宿主 Activity 分离后,系统会调用 onDetach() 回调。该 Fragment 不再处于活跃状态,无法再使用 findFragmentById() 检索到。
首先通过源码可以知道,Fragment类 会实现 LifecycleOwner,LifecycleOwner内部有一个方法Lifecycle getLifecycle(),返回的是一个Lifecycle 对象;
Lifecycle 是一个抽象类生命周期状态状态均在 Lifecycle.State 枚举中表示。
/**
* Lifecycle states. You can consider the states as the nodes in a graph and
* {@link Event}s as the edges between these nodes.
*/
@SuppressWarnings("WeakerAccess")
public enum State {
/**
* Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
* any more events. For instance, for an {@link android.app.Activity}, this state is reached
* <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call.
*/
DESTROYED,
/**
* Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is
* the state when it is constructed but has not received
* {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet.
*/
INITIALIZED,
/**
* Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call;
* <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call.
* </ul>
*/
CREATED,
/**
* Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onStart() onStart} call;
* <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
* </ul>
*/
STARTED,
/**
* Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached after {@link android.app.Activity#onResume() onResume} is called.
*/
RESUMED;
/**
* Compares if this State is greater or equal to the given {@code state}.
*
* @param state State to compare with
* @return true if this State is greater or equal to the given {@code state}
*/
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
顺着我们重写的声明周期方法向上追,就是下面的顺序:先进入Fragment类中onCreate方法 然后是被 performxx方法调用,这些个performxx都是被FragmentManagerImpl的moveToState方法区分了状态来调用的。以下是以onCreate 和onResume 为例,其他生命周期方法也是一样。
Fragment类中onCreate - performCreate - FragmentManagerImpl的moveToState
Fragment类中onResume - performResume - FragmentManagerImpl的moveToState
Fragment类中定义了这些常量和一个变量mState ,mState 就是记录这些常量的一个变量值。最后都是把上面枚举值转变为这个这些常量用mState 再进行调用我们熟知的生命周期方法。
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // Fully created, not started.
static final int STARTED = 3; // Created and started, not resumed.
static final int RESUMED = 4; // Created started and resumed.
int mState = INITIALIZING;
FragmentManagerImpl的moveToState方法非常重要,但是代码行数很多,这贴出一部分图您就大致明了了。截图部分可以看到有两个分支分别调用了performPause()和performStop()
- 动态加载Fragment的原理解析
add和replaca方法:
FragmentTransaction类的 - add - doAddOp - addOp -
FragmentTransactiond类的 - replace - doAddOp - addOp -
两个方法执行路线极为相似,只在doAddOp方法传入里两个不同的值OP_ADD和OP_REPLACE,也就决定了后面的处理一定会依赖这两个值。
@NonNull
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
//======
@NonNull
public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag) {
if (containerViewId == 0) {
throw new IllegalArgumentException("Must use non-zero containerViewId");
}
doAddOp(containerViewId, fragment, tag, OP_REPLACE);
return this;
}
上面提到过操作fragment必须执行提交操作,否则无效。所以commit才是关键。
调用commit方法:
FragmentTransaction也是个抽象类,它的子类实现类是BackStackRecord。
BackStackRecord类 - commit - commitInternal - 调用FragmentManagerImpl类 - enqueueAction -scheduleCommit - updateOnBackPressedCallbackEnabled - tmHost.getHandler().post(mExecCommit)将任务发到run方法执行 - execPendingActions - removeRedundantOperationsAndExecute - executeOpsTogether - 调用BackStackRecord类 - expandOps, expandOps方法是核心处理逻辑。