当前位置: 首页 > news >正文

【Android Framework系列】第14章 Fragment核心原理(AndroidX版本)

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的版本代码不断在更新,状态机也不断在变化,因此我们主要分析重点的状态机思路

INITIALIZED:Fragment 的一个新实例已实例化。
CREATED:系统已调用第一批 Fragment 生命周期方法。在 Fragment 处于此状态期间,系统也会创建与其关联的视图。
STARTED:Fragment 在屏幕上可见,但没有焦点,这意味着其无法响应用户输入。
RESUMED:Fragment 可见并已获得焦点。
DESTROYED:Fragment 对象已解除实例化。

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()方法为例,可以看到调用了mFragmentsdispatchCreate()方法。然后调用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:...}}...
}
  1. 小伙伴们有没发现上面代码的特别之处?case里面没有break
    这样的好处,是为了让Fragment走完整的生命周期
  2. 触发状态转移时,首先会判断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 事务概述

  1. 事务的特性是什么?
    事务是恢复和并发的基本单位,具备4个基本特性:
    原子性:事务不可分割,要么全部完成,要么全部失败回滚;
    一致性:事务执行前后数据都具有一致性;
    隔离性:事务执行过程中,不受其他事务干扰;
    持久性:事务一旦完成,对数据的改变就是永久的。在Android中体现为Fragment状态保存后,commit()提交事务会抛异常,因为这部分新提交的事务影响的状态无法保存。

  2. 事务的作用是什么?
    使用事务FragmentTransaction可以动态改变Fragment状态,使得Fragment在一定程度脱离宿主的状态。不过,事务依然受到宿主状态约束,例如:当前Activity处于STARTED状态,那么addFragment不会使得Fragment进入RESUME状态。只有将来Activity进入RESUME状态时,才会同步Fragment到最新状态。

3.2 不同事务操作的区别

  1. add&remove:Fragment状态在INITIALIZINGRESUMED之间转移;
  2. detach&attach:Fragment状态在CREATERESUMED之间转移;
  3. replace:先移除所有containerId中的实例,再add一个Fragment;
  4. show&hide:只控制Fragment隐藏显示,不会触发状态转移,也不会销毁Fragment视图或实例;
  5. hide&detach&removehide不会销毁视图和实例、detach只销毁视图不销毁实例、remove会销毁实例(自然也销毁视图)。不过,如果remove的时候将事务添加到回退栈,那么Fragment实例就不会被销毁,只会销毁视图。
    在这里插入图片描述
    需要注意detach Fragment 并不会回调 onDetach(),而是转移到CREATE 状态,回调 onDetach() 需要转移到 INITIALIZING(是不是很奇葩的起名!)

3.3 不同事务提交方式

FragmentTransaction 定义了 5 种提交方式:
在这里插入图片描述
需要注意的地方:

  1. onSaveInstanceState()保存状态后,事务形成的新状态是不会被保存的。在状态保存之后调用 commit()commitNow()会抛异常,我们需要使用commitAllowingStateLoss()commitNowAllowingStateLoss()进行提交,我们可以看下抛异常的具体代码:

FragmentManagerImpl.java

private void checkStateLoss() {if (mStateSaved || mStopped) {throw new IllegalStateException("Can not perform this action after onSaveInstanceState");}
}
  1. 使用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;
}  
  1. commitNow()executePendingTransactions() 都是同步执行,有区别吗?
    commitNow()是同步执行当前事务,而executePendingTransactions()是同步执行事务队列中的全部事务。

4 Fragment逻辑流程

Fragment的逻辑流程本章节不做详细分析,贴上调用关系图供小伙伴们参考学习。

FragmentActivity到FragmentManager的相关调用关系图:
在这里插入图片描述
FragmentManager和BackStackRecord回退栈项的调用关系图:
在这里插入图片描述

5 总结

本章节我们主要了解Fragment的两大模块:

  1. 生命周期及状态 :生命周期状态密切相关,状态机升序降序来实现生命周期的对应。
  2. 事务管理:commit()commitNow()commitAllowingStateLoss()commitNowAllowingStateLoss()executePendingTransactions()的区别分析。

相关文章:

【Android Framework系列】第14章 Fragment核心原理(AndroidX版本)

1 简介 Fragment是一个历史悠久的组件&#xff0c;从API 11引入至今&#xff0c;已经成为Android开发中最常用的组件之一。 Fragment表示应用界面中可重复使用的一部分。Fragment定义和管理自己的布局&#xff0c;具有自己的生命周期&#xff0c;并且可以处理自己的输入事件。…...

Python 网页爬虫原理及代理 IP 使用

目录 前言 一、Python 网页爬虫原理 二、Python 网页爬虫案例 步骤1&#xff1a;分析网页 步骤2&#xff1a;提取数据 步骤3&#xff1a;存储数据 三、使用代理 IP 四、总结 前言 随着互联网的发展&#xff0c;网络上的信息量变得越来越庞大。对于数据分析人员和研究人…...

失效的访问控制及漏洞复现

失效的访问控制(越权) 1. 失效的访问控制(越权) 1.1 OWASP TOP10 1.1.1 A5:2017-Broken Access Control 未对通过身份验证的用户实施恰当的访问控制。攻击者可以利用这些缺陷访问未经授权的功能或数据&#xff0c;例如&#xff1a;访问其他用户的帐户、查看敏感文件、修改其…...

MLOps:掌握机器学习部署:Docker、Kubernetes、Helm 现代 Web 框架

介绍&#xff1a; 在机器学习的动态世界中&#xff0c;从开发模型到将其投入生产的过程通常被认为是复杂且多方面的。 然而&#xff0c;随着 Docker、Kubernetes 等工具以及 FastAPI、Streamlit 和 Gradio 等用户友好的 Web 框架的出现&#xff0c;这一过程变得比以往更加简化…...

Python标识符命名规范

简单地理解&#xff0c;标识符就是一个名字&#xff0c;就好像我们每个人都有属于自己的名字&#xff0c;它的主要作用就是作为变量、函数、类、模块以及其他对象的名称。 Python 中标识符的命名不是随意的&#xff0c;而是要遵守一定的命令规则&#xff0c;比如说&#xff1a;…...

对 fastq 和 bam 进行 downsample

对 fastq 和 bam 进行 downsample 一、Fastq1、seqtk二、Bam1、samtools2、Picard DownsampleSam3、比较 并行采样模板 一、Fastq 1、seqtk Seqtk 是一种快速轻量级的工具&#xff0c;用于处理 FASTA 或 FASTQ 格式的序列。 它可以无缝解析 FASTA 和 FASTQ 文件&#xff0c;这…...

网络爬虫:如何有效的检测分布式爬虫

分布式爬虫是一种高效的爬虫方式&#xff0c;它可以将爬虫任务分配给多个节点同时执行&#xff0c;从而加快爬虫的速度。然而&#xff0c;分布式爬虫也容易被目标网站识别为恶意行为&#xff0c;从而导致IP被封禁。那么&#xff0c;如何有效地检测分布式爬虫呢&#xff1f;本文…...

elementUI可拖拉宽度抽屉

1&#xff0c;需求&#xff1a; 在elementUI的抽屉基础上&#xff0c;添加可拖动侧边栏宽度的功能&#xff0c;实现效果如下&#xff1a; 2&#xff0c;在原组件上添加自定义命令 <el-drawer v-drawerDrag"left" :visible.sync"drawerVisible" direc…...

OpenPCDet系列 | 8.4 nuScenes数据集数据调用和数据分析

文章目录 1. 对数据集遍历1.1 统计mini版本的nuScenes各模态数据和关键帧的数量1.2 单独遍历lidar模态数据1.3 遍历scene统计数据1.4 遍历sample统计数据1.5 遍历sample_data统计数据1.6 数据集的底层结构2. 对数据集可视化2.1 render_sample和render_sample_data2.2 nusc.rend…...

WeiTitlePopupWindow

目录 1 WeiTitlePopupWindow 1.1 // 设置可点击 1.2 // 设置弹窗外可点击 1.3 // 设置弹窗宽度和高度 1.4 // 设置弹窗布局界面 WeiTitlePopupWindow // 设置可点击setTouchable(true);...

qemu/kvm学习笔记

qemu/kvm架构 cpu虚拟化的示例 Reference: kvmtest.c [LWN.net] 主要步骤&#xff1a; QEMU通过/dev/kvm设备文件发起KVM_CREATE_VM ioctl&#xff0c;请求KVM创建一个虚拟机。KVM创建虚拟机相应的结构体&#xff0c;并为QEMU返回一个虚拟机文件描述符QEMU通过虚拟机文件描述…...

android 车载widget小部件部分详细源码实战开发-千里马车载车机framework开发实战课程

官网参考链接&#xff1a;https://developer.android.google.cn/develop/ui/views/appwidgets/overview 1、什么是小部件 App widgets are miniature application views that can be embedded in other applications (such as the home screen) and receive periodic updates…...

如何使用CSS画一个三角形

原理&#xff1a;其实就是规定元素的四个边框颜色及边框宽度&#xff0c;将元素宽高设置为0。如果要哪个方向的三角形&#xff0c;将对应其他三个方向的边框宽和颜色设置为0和透明transparent即可 1.元素设置边框&#xff0c;宽高&#xff0c;背景色 <style>.border {w…...

第15章_锁: (表级锁、页级锁、行锁、悲观锁、乐观锁、全局锁、死锁)

3.2 从数据操作的粒度划分&#xff1a;表级锁、页级锁、行锁 为了提高数据库并发度&#xff0c;每次锁定的数据范围越小越好&#xff0c;理论上每次只锁定当前操作的数据的方案会得到最大的并发度&#xff0c;但管理锁是很耗资源&#xff08;涉及获取、检查、释放锁等动作)。因…...

python音频转文字调用baidu

python音频转文字调用的是百度智能云的接口&#xff0c;因业务需求会涉及比较多数字&#xff0c;所以这里做了数字的处理&#xff0c;可根据自己的需求修改。 from flask import Flask, request, jsonify import requestsfrom flask_limiter import Limiterapp Flask(__name_…...

靶场溯源第二题

关卡描述&#xff1a;1. 网站后台登陆地址是多少&#xff1f;&#xff08;相对路径&#xff09; 首先这种确定的网站访问的都是http或者https协议&#xff0c;搜索http看看。关于http的就这两个信息&#xff0c;然后172.16.60.199出现最多&#xff0c;先过滤这个ip看看 这个很…...

mysql 的增删改查以及模糊查询、字符集语句的使用

一、mysql启动与登陆(windows下的mysql操作) 1.启动mysql服务 net start mysql81 2.登陆mysql mysql -uroot -p 3.查看所有数据库 show databases; 二、模糊查询&#xff08;like&#xff09; 1. _代表查询单个 2.%代表查询多个 3.查找所有含有schema的数据库&#xff1b;…...

Python Django框架中文教程:学习简单、灵活、高效的Web应用程序框架

概述: Python Django是一种流行的Web应用程序框架&#xff0c;被广泛应用于开发高效、可扩展的网站和Web应用程序。Django以其简单、灵活和高效而受到开发者们的青睐。它提供了强大的工具和功能&#xff0c;使开发过程更加容易和高效。 Django的主要目标是帮助开发者快速构建…...

Docker认识即安装

Docker及相关概念 Docker和虚拟机方式的区别&#xff1a;虚拟机技术是虚拟出一套硬件后&#xff0c;在其上运行一个完整的操作系统&#xff0c;在该系统上在运行所需应用进程&#xff1b;而容器内的应用进程是直接运行于宿主的内核&#xff0c;容器内没有自己的内核&#xff0…...

chrome 谷歌浏览器 导出插件拓展和导入插件拓展

给同事部署 微软 RPA时&#xff0c;需要用到对应的chrome浏览器插件&#xff1b;谷歌浏览器没有外网是不能直接下载拓展弄了半小时后才弄好&#xff0c;竟发现没有现成的教程&#xff0c;遂补充&#xff1b; 如何打包导出 谷歌浏览器 地址栏敲 chrome://extensions/在对应的地…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...