展开说说:Android Fragment完全解析-卷三

embedded/2024/12/22 1:55:13/

本文章分析了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;

FragmentManagerImplmoveToState方法非常重要,但是代码行数很多,这贴出一部分图您就大致明了了。截图部分可以看到有两个分支分别调用了performPause()和performStop()

  1. 动态加载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方法是核心处理逻辑。


http://www.ppmy.cn/embedded/31598.html

相关文章

【论文阅读】Tutorial on Diffusion Models for Imaging and Vision

1.The Basics: Variational Auto-Encoder 1.1 VAE Setting 自动编码器有一个输入变量x和一个潜在变量z Example. 获得图像的潜在表现并不是一件陌生的事情。回到jpeg压缩&#xff0c;使用离散余弦变换&#xff08;dct&#xff09;基φn对图像的底层图像/块进行编码。如果你给…

使用Postman对@RequestPart和HttpServletRequest组合传参方式

使用Postman对RequestPart和HttpServletRequest组合传参方式 方法代码如下&#xff1a; /*** 发布*/ApiOperation("发布")ApiImplicitParams({ApiImplicitParam(name "req", value "json格式", dataType "Map", dataTypeClass Ma…

【Python可视化】pyecharts

Echarts 是一个由百度开源的数据可视化&#xff0c;凭借着良好的交互性&#xff0c;精巧的图表设计&#xff0c;得到了众多开发者的认可。而 Python 是一门富有表达力的语言&#xff0c;很适合用于数据处理。当数据分析遇上数据可视化时&#xff0c;pyecharts 诞生了。 需要安…

C# Solidworks二次开发:枚举应用实战(第十三讲)

大家好&#xff0c;今天继续介绍我们的枚举应用系列。 下面是今天要介绍的枚举&#xff1a; &#xff08;1&#xff09;第一个为swsUserPreferenceIntegerValue_e&#xff0c;这个枚举的含义为用户偏好整数值&#xff0c;下面是官方的具体枚举值&#xff1a; MemberDescript…

RHCE shell-第一次作业

要求&#xff1a; 1、判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检査- 次磁盘剩余空间。 2、判断web服务是否运行(1、查看进程的方式判断该程序是否运行&#xff0c;2、通过查看端口的方式 判断该程序是否运…

Spark使用Java读取Mysql

在Apache Spark中使用Java来读取MySQL数据库中的数据&#xff0c;你需要使用JDBC&#xff08;Java Database Connectivity&#xff09;来连接MySQL&#xff0c;并且通常你会使用Spark的JdbcRDD或者DataFrameReader&#xff08;通过Spark SQL&#xff09;来读取数据。不过&#…

一对一WebRTC视频通话系列(二)——websocket和join信令实现

本系列博客主要记录WebRtc实现过程中的一些重点&#xff0c;代码全部进行了注释&#xff0c;便于理解WebRTC整体实现。 一对一WebRTC视频通话系列往期博客&#xff1a; 一对一WebRTC视频通话系列&#xff08;一&#xff09;—— 创建页面并显示摄像头画面 websocket和join信令…

微信小程序之方法调用报错(TypeError: Cannot read property ‘RegisterStatues‘ of undefined)

出现错误&#xff1a;TypeError: Cannot read property RegisterStatues of undefined&#xff0c;实际无法调用其他方法和变量&#xff0c;如&#xff1a;在handleRegister函数中无法调用RegisterStatues函数。 原因&#xff1a;因为在success回调函数中&#xff0c;this指向…