石家庄市制作网站公司,品牌设计师,wordpress搜索 s=,人才招聘网最新招聘信息1 简介
Fragment是一个历史悠久的组件#xff0c;从API 11引入至今#xff0c;已经成为Android开发中最常用的组件之一。 Fragment表示应用界面中可重复使用的一部分。Fragment定义和管理自己的布局#xff0c;具有自己的生命周期#xff0c;并且可以处理自己的输入事件。…1 简介
Fragment是一个历史悠久的组件从API 11引入至今已经成为Android开发中最常用的组件之一。 Fragment表示应用界面中可重复使用的一部分。Fragment定义和管理自己的布局具有自己的生命周期并且可以处理自己的输入事件。Fragment不能独立存在而是必须由Activity或另一个Fragment托管。Fragment的视图层次结构会成为宿主的视图层次结构的一部分或附加到宿主的视图层次结构。 本章节主要探索Fragment的生命周期状态及事务管理。
2 Fragment生命周期
2.1 Fragment完整生命周期
onAttach - onCreate - onCreatedView - onActivityCreated - onStart - onResume - onPause - onStop - onDestroyView - onDestroy - onDetach 如下图所示 Fragment与Activity生命周期各状态的对比
2.2 Fragment生命周期状态
Fragment的生命周期状态只有5个通过降序以及升序来进行判断。如果是升序走显示的生命周期降序为销毁的生命周期。由于Fragment的版本代码不断在更新状态机也不断在变化因此我们主要分析重点的状态机思路 INITIALIZEDFragment 的一个新实例已实例化。 CREATED系统已调用第一批 Fragment 生命周期方法。在 Fragment 处于此状态期间系统也会创建与其关联的视图。 STARTEDFragment 在屏幕上可见但没有焦点这意味着其无法响应用户输入。 RESUMEDFragment 可见并已获得焦点。 DESTROYEDFragment 对象已解除实例化。 FragmentManagerImpl利用mCurState成员变量来标记当前状态Fragment利用mState成员变量来标记当前状态。 更新FragmentManagerImpl的生命周期状态这里以FragmentActivity的生命周期回调开始先看派发给FragmentManagerImpl各个状态的时机。 FragmentManagerImpl继承自FragmentManagerFragmentActivity通过生命周期调用Fragment的生命周期其实就是调用了FragmentManagerImpl这个类来进行分发最终都是走的dispatchStateChange()方法进行状态机的更新。
FragmentActivity.java Overrideprotected void onCreate(Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);mFragments.dispatchCreate();}我们以FragmentActivity#onCreate()方法为例可以看到调用了mFragments的dispatchCreate()方法。然后调用FragmentManager的dispatchCreate()方法。
FragmentManager.java
//源码方法跳转太多我直接帮你梳理出核心流程跟你直接看源码会不同但逻辑是相同的
public void dispatchCreate() {mStateSaved false;mStopped false;moveToState(Fragment.CREATED, false);// 4、处理未执行的事务execPendingActions();
}void moveToState(int newState, boolean always) {// 1、状态判断if (nextState mCurState) {return;}mCurState nextState;// 2、执行添加的 Fragment// Must add them in the proper order. mActive fragments may be out of orderfor (int i 0; i mAdded.size(); i) {Fragment f mAdded.get(i);// 更新 Fragment 到当前状态moveFragmentToExpectedState(f);}// 3、执行未添加但是准备移除的 Fragment// Now iterate through all active fragments. These will include those that are removed and detached.for (int i 0; i mActive.size(); i) {Fragment f mActive.valueAt(i);if (f ! null (f.mRemoving || f.mDetached) !f.mIsNewlyAdded) {// 更新 Fragment 到当前状态moveFragmentToExpectedState(f);}}
}其中moveFragmentToExpectedState() 最终调用到moveToState(Fragment, int)
// moveFragmentToExpectedState 最终调用到
// 更新 Fragment 到当前状态
void moveToState(Fragment f, int newState) {// 1、准备 Detatch Fragment 的情况不再与宿主同步进入 CREATED 状态if ((!f.mAdded || f.mDetached) newState Fragment.CREATED) {newState Fragment.CREATED;}// 2、移除 Fragment 的情况Fragment 不再与宿主同步if (f.mRemoving newState f.mState) {if (f.isInBackStack()) {// 2.1 移除动作添加到返回栈则进入 CREATED 状态newState Math.min(nextState, Fragment.CREATED);} else {// 2.1 移除动作添加到返回栈则进入 DESTROY 状态newState Math.min(nextState, Fragment.INITIALIZING);}}// 3、真正执行状态转移if (f.mState newState ) {switch (f.mState) {case Fragment.INITIALIZING:if (nextState Fragment.INITIALIZING) {...}// fall throughcase Fragment.CREATED:...// fall throughcase Fragment.ACTIVITY_CREATED:...// fall throughcase Fragment.STARTED:...}} else {switch (f.mState) {case Fragment.RESUMED:if (newState Fragment.RESUMED) {...}// fall throughcase Fragment.STARTED:...// fall throughcase Fragment.ACTIVITY_CREATED:...// fall throughcase Fragment.CREATED:...}}...
}小伙伴们有没发现上面代码的特别之处case里面没有break。 这样的好处是为了让Fragment走完整的生命周期触发状态转移时首先会判断Fragment如果已经处于目标状态newState则会跳过状态转移。然而并不是FragmentManager里所有的Fragment都会执行状态转移只有「mAdded为真mDetached为假」的Fragment才会更新到目标状态其他Fragment会脱离宿主状态。最后状态转移完成后会处理未执行的事务execPendingActions();可见每次dispatchXXX()都会提供一次事务执行的窗口。 不同Fragment标志位Detach/Remove/返回栈与最终状态的关系总结如下表 提示 这些标志位可以通过事务进行干涉。
2.3 Fragment的生命周期对应状态
升序 onCreate()Fragment已实例化并处于CREATED状态。不过其对应的视图尚未创建。 onCreateView()此方法可用于创建布局。Fragment已进入CREATED状态。 onViewCreated()此方法在创建视图后调用。在此方法中您通常会通过调用findViewById()将特定视图绑定到属性。 onStart()Fragment已进入STARTED状态。 onResume()Fragment已进入RESUMED状态现已具有焦点可响应用户输入。
降序 onPause()Fragment已重新进入STARTED状态。相应界面对用户可见。 onStop()Fragment已重新进入CREATED状态。该对象已实例化但它在屏幕上不再显示。 onDestroyView()该方法在Fragment进入DESTROYED状态之前调用。视图已从内存中移除但Fragment对象仍然存在。 onDestroy()Fragment进入DESTROYED状态。
下图总结了Fragment生命周期以及状态之间的转换
3 Fragment 事务管理
下面我们来了解下影响 Fragment 状态转移的第二个因素事务。
3.1 事务概述 事务的特性是什么 事务是恢复和并发的基本单位具备4个基本特性 原子性事务不可分割要么全部完成要么全部失败回滚 一致性事务执行前后数据都具有一致性 隔离性事务执行过程中不受其他事务干扰 持久性事务一旦完成对数据的改变就是永久的。在Android中体现为Fragment状态保存后commit()提交事务会抛异常因为这部分新提交的事务影响的状态无法保存。 事务的作用是什么 使用事务FragmentTransaction可以动态改变Fragment状态使得Fragment在一定程度脱离宿主的状态。不过事务依然受到宿主状态约束例如当前Activity处于STARTED状态那么addFragment不会使得Fragment进入RESUME状态。只有将来Activity进入RESUME状态时才会同步Fragment到最新状态。
3.2 不同事务操作的区别
addremoveFragment状态在INITIALIZING与RESUMED之间转移detachattachFragment状态在CREATE与RESUMED之间转移replace先移除所有containerId中的实例再add一个Fragmentshowhide只控制Fragment隐藏或显示不会触发状态转移也不会销毁Fragment视图或实例hidedetachremovehide不会销毁视图和实例、detach只销毁视图不销毁实例、remove会销毁实例自然也销毁视图。不过如果remove的时候将事务添加到回退栈那么Fragment实例就不会被销毁只会销毁视图。 需要注意detach Fragment 并不会回调 onDetach()而是转移到CREATE 状态回调 onDetach() 需要转移到 INITIALIZING是不是很奇葩的起名
3.3 不同事务提交方式
FragmentTransaction 定义了 5 种提交方式 需要注意的地方
onSaveInstanceState()保存状态后事务形成的新状态是不会被保存的。在状态保存之后调用 commit()或commitNow()会抛异常我们需要使用commitAllowingStateLoss()和commitNowAllowingStateLoss()进行提交我们可以看下抛异常的具体代码
FragmentManagerImpl.java
private void checkStateLoss() {if (mStateSaved || mStopped) {throw new IllegalStateException(Can not perform this action after onSaveInstanceState);}
}使用commitNow()或commitNowAllowingStateLoss()提交的事务不允许加入回退栈
为什么有这个设计呢可能是 Google 考虑到同时存在同步提交和异步提交的事务并且两个事务都要加入回退栈时无法确定哪个在上哪个在下是符合预期的所以干脆禁止 commitNow() 加入回退栈这里记住带Now的提交为同步提交不加入回退栈中。如果确实有需要同步执行回退栈的应用场景可以采用commit() executePendingTransactions()的取巧方法。相关源码体现如下
BackStackRecord.java
Override
public void commitNow() {disallowAddToBackStack();mManager.execSingleAction(this, false);
}Override
public void commitNowAllowingStateLoss() {disallowAddToBackStack();mManager.execSingleAction(this, true);
}
NonNull
public FragmentTransaction disallowAddToBackStack() {if (mAddToBackStack) {throw new IllegalStateException(This transaction is already being added to the back stack);}mAllowAddToBackStack false;return this;
} commitNow() 和 executePendingTransactions() 都是同步执行有区别吗 commitNow()是同步执行当前事务而executePendingTransactions()是同步执行事务队列中的全部事务。
4 Fragment逻辑流程
Fragment的逻辑流程本章节不做详细分析贴上调用关系图供小伙伴们参考学习。
FragmentActivity到FragmentManager的相关调用关系图 FragmentManager和BackStackRecord回退栈项的调用关系图
5 总结
本章节我们主要了解Fragment的两大模块
生命周期及状态 生命周期和状态密切相关状态机升序和降序来实现生命周期的对应。事务管理commit()、commitNow()、commitAllowingStateLoss()、commitNowAllowingStateLoss()及executePendingTransactions()的区别分析。