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

【Android】【底层机制】组件生命周期以及背后的状态管理

以下让我们直接切入本质,串联起应用层、AMS和进程模型


核心思想:生命周期是“状态机”

首先,请建立一个核心认知:生命周期回调(onCreate, onStart等)是系统管理组件状态变化时给我们的“钩子”(Hook)。整个系统实际上在维护一个复杂的状态机


一、 Activity生命周期:从表象到本质

1. 经典生命周期图谱

您一定熟悉这张图,但我们不再赘述每个回调的简单含义,而是直接探讨其状态分组设计意图

  • 三种核心生命周期
    • 完整生命周期:从 onCreate()onDestroy()。关注资源的初始化和释放
    • 可见生命周期:从 onStart()onStop()。关注UI的展示和隐藏。此时Activity可能部分可见(如有其他透明Activity),但已进入用户视野。
    • 前台生命周期:从 onResume()onPause()。关注用户交互。此时Activity位于栈顶,接收输入事件。
2. 深度剖析:状态变化的驱动者

关键问题:是谁在调用我们的onCreateonResume等方法?

答案:系统服务——AMS(ActivityManagerService)

  • AMS的角色:它是Android系统的“大脑”,负责所有四大组件的调度和状态管理。它维护着一个Activity栈(ActivityStack/Task),记录着每个Activity的状态(ActivityRecord)。
  • 进程内执行者——ActivityThread:我们的应用进程有一个主线程类叫ActivityThread,它有一个内部类H(Handler)。AMS通过Binder IPC通知ActivityThread状态变化,H再切换到主线程,反射调用我们Activity的对应生命周期方法。

一个启动流程的深度追溯:

  1. 应用进程ActivityA 调用 startActivity(Intent)
  2. Binder调用:请求经由ActivityTaskManager(ATM)的Binder代理,发送到系统进程的AMS。
  3. AMS决策:AMS检查权限、创建或复用目标进程、创建ActivityRecord、决定启动模式(如何放入栈)。
  4. 暂停当前Activity:AMS通过Binder通知ActivityThread暂停ActivityA,执行onPause()onPause必须快速完成,否则会阻塞下一个Activity的启动
  5. 启动目标Activity:AMS确认ActivityA已Paused后,通知目标应用进程的ActivityThread
  6. 创建实例ActivityThread通过ClassLoader创建ActivityB实例。
  7. 状态回调ActivityThread依次调用ActivityBonCreate() -> onStart() -> onResume()
  8. 窗口管理:在这个过程中,ActivityThread还会与WindowManagerService(WMS)通信,创建PhoneWindowDecorView,并最终通过ViewRootImpl完成UI的测量、布局、绘制。
  9. 完成启动ActivityB进入Resumed状态,AMS将ActivityA完全Stop(如果被完全覆盖)。

C++视角:这里的Binder IPC是整个过程的核心瓶颈和设计关键。AMS在system_server进程,我们的App在独立进程,所有状态同步都依赖Binder。理解Binder的mmap和一次拷贝机制,能帮你理解为何Android要如此设计生命周期的异步回调模型。


二、 状态保存与恢复:与“进程杀手”的博弈

这是生命周期中最易被误解,也最能体现框架设计智慧的部分。

1. 场景:配置变更(如屏幕旋转)
  • 现象:Activity被销毁并重建。
  • 系统意图:为了让应用重新加载匹配新配置的资源(如横向布局)。
  • 数据流转
    1. 销毁前:系统调用 onSaveInstanceState(Bundle outState)。我们将需要恢复的数据(如用户输入的临时文本)存入Bundle
    2. 重建时onCreate(Bundle savedInstanceState)onRestoreInstanceState(Bundle savedInstanceState) 都会收到这个Bundle
  • Bundle的数据存在哪里?
    * :这个Bundle会被AMS通过Binder传递并暂存在系统进程的内存中。当Activity重建时,AMS再将其传回应用进程。这就是为什么Bundle内必须是可序列化的轻量数据,且大小限制为1MB。
2. 场景:后台进程被杀死
  • 现象:App在后台,系统内存不足时,可能会杀死我们的进程。当用户切回时,Activity会重建。
  • 系统意图:Android不是桌面系统,移动设备资源有限。系统需要优先保证前台进程的资源。
  • 数据流转:与配置变更类似,也是通过onSaveInstanceStateonCreate中的Bundle来恢复。但这里更不可靠,因为系统可能在内存极低时,连保存状态的机会都不给就直接杀死进程。

三、 Fragment生命周期:更复杂的状态嵌套

Fragment的生命周期可以看作是Activity生命周期的“微缩版”和“依赖版”。

1. 与宿主的同步
  • Fragment的生命周期完全由其宿主Activity和父FragmentManager驱动
  • 核心状态:ATTACHED -> CREATED -> STARTED -> RESUMED
  • :为什么会出现Fragment重叠?
    * :根本原因是状态恢复时机。在配置变更(如旋转)后,Activity重建,系统会自动通过FragmentManager恢复之前的状态(包括重新创建Fragment实例)。如果开发者在onCreate中又再次add了一个新的Fragment,就会导致重复添加。解决方案:在onCreate中添加Fragment时,先检查savedInstanceState是否为null。
        if (savedInstanceState == null) {// 只有第一次创建Activity时才添加FragmentgetSupportFragmentManager().beginTransaction().add(R.id.container, MyFragment.newInstance()).commit();}// 否则,交给系统自动恢复
2. View生命周期

Fragment的View有自己独立的生命周期(onCreateView, onDestroyView)。这意味着Fragment对象可以存在,但其View可以被销毁和重建。这是很多内存泄漏和空指针问题的根源。

  • 最佳实践:在onDestroyView中,清空所有对View的引用(特别是那些可能持有Activity引用的View,如Dialog)。

四、 背后的状态管理机制

1. ActivityStack与Task
  • ActivityStack:AMS内部管理Activity的栈结构。它决定了Activity的启动、调度和返回逻辑。
  • Task:一个逻辑上的“任务”,由一系列相关的Activity组成。用户感知为一个“应用”。一个Task可以跨进程包含不同应用的Activity。
  • 启动模式(Launch Mode)standard, singleTop, singleTask, singleInstance。这些模式本质上是在告诉AMS,如何将新的ActivityRecord与现有的Task和Stack进行关联。
2. 进程优先级与OOM_ADJ

系统根据组件状态决定进程的优先级,优先级低的进程在内存不足时会被优先杀死。

进程状态示例优先级被杀风险
前台进程 (Foreground)拥有Resumed状态的Activity最高几乎不可能
可见进程 (Visible)拥有Paused但可见的Activity(如弹窗后的Activity)
服务进程 (Service)运行着Service(非前台)中等中等
后台进程 (Background)拥有Stopped状态的Activity(用户不可见)
空进程 (Empty)无任何活跃组件,仅为缓存最低最先

系统逻辑:当需要内存时,系统从最低优先级的进程开始杀起,同时会尝试调用其组件的onSaveInstanceState来保存状态。


五、 现代架构的演进:解耦与状态持久化

传统生命周期管理存在痛点:状态保存与业务逻辑耦合过紧,且在配置变更时无法轻松保留数据(如网络请求结果)。

Jetpack架构组件提供了优雅的解决方案:

  1. ViewModel

    • 设计目标以生命周期的方式管理界面相关的数据
    • 生命周期:它的作用域从Activity首次创建直到其最终销毁(Finishing),跨越了配置变更导致的临时销毁
    • 背后原理ViewModel对象被存储在ViewModelStore中,而ViewModelStoreActivity(或Fragment)的非配置实例(即不会被重建的对象)持有,或者在配置变更时通过onRetainNonConfigurationInstance()机制暂存并传递。
    • onSaveInstanceState互补
      • ViewModel:存“暂态数据”,如用户对象、网络数据列表。数据在内存中,读写快。
      • onSaveInstanceState:存“关键状态”,如用户ID、编辑框内容。数据需要序列化,用于应对进程被杀死的极端情况。
  2. Lifecycle

    • 设计目标:将生命周期状态抽象为一个可观察的对象,让任何类都能感知到生命周期的变化。
    • 背后原理ActivityFragment实现了LifecycleOwner接口,内部维护一个LifecycleRegistry。当生命周期回调时,会通知LifecycleRegistry状态变化,进而分发给所有注册的LifecycleObserver(如LiveData)。
    • 价值:实现了业务逻辑(如位置更新、相机预览)与UI生命周期的自动解耦

面试表达策略

当被问及生命周期时,可以构建一个由浅入深的回答:

  1. 总起:“我对生命周期的理解,不仅仅是几个回调方法的顺序,而是一套由系统服务驱动的、用于管理组件状态和系统资源的完整机制。”
  2. 分述
    • “从应用层看,我们熟悉onCreateonDestroy的流程,它定义了资源的初始化、UI的展示隐藏和用户交互的边界。”
    • “但驱动这一切的,是系统进程的AMS。它通过Binder IPC与我们的ActivityThread通信,像一个状态机一样,指挥着我们应用内组件的状态变迁。比如启动一个新Activity,会先暂停旧的,再创建和恢复新的。”
    • “为了应对系统资源回收和配置变更,框架设计了onSaveInstanceState机制,将关键状态通过Bundle暂存在系统服务端,在重建时恢复。但这有其局限性,所以现代架构推出了ViewModel,它在内存中持久化数据,优雅地解决了配置变更时的数据保留问题。”
    • “最后,这一切都与进程优先级模型紧密相关。系统根据组件的生命周期状态来决定进程的OOM_ADJ值,优先回收后台进程,以保证前台应用的流畅体验。”
  3. 结合经验
    • “在我的开发经验中,深刻理解这套机制帮助我避免了无数内存泄漏和状态管理错误。例如,我会在ViewModel中持有数据,在onSaveInstanceState中只保存最小必要的恢复信息,并使用Lifecycle来让网络请求等异步任务自动在页面销毁时取消。”
  4. 收尾:“所以,‘熟练掌握’对我而言,意味着能从API层面,一直深入到AMS、Binder和进程管理的系统层,并能够运用现代架构工具设计出健壮、可维护的状态管理方案。”
http://www.dtcms.com/a/490057.html

相关文章:

  • CPM:CMake 包管理详细介绍
  • D3.js + SVG:数据可视化领域的黄金搭档,绘制动态交互图表。
  • 【个人成长笔记】在 QT 中 SkipEmptyParts 编译错误信息及其解决方案
  • 设计模式篇之 备忘录模式 Memento
  • dw做的网站放文件夹网页生成桌面快捷方式
  • 2017流行的网站风格随州网站建设价格
  • 鸿蒙:使用媒体查询监听屏幕方向、切换横竖屏
  • 8.list的使用
  • 网页跳转github镜像
  • 安灯系统(Andon)如何为汽车工厂打造零延迟响应
  • C++(条件判断与循环)
  • 温州建设局网站首页中国企业名录黄页
  • linux/centos迁移conda文件夹
  • Quill 富文本编辑器 功能介绍,使用场景说明,使用示例演示
  • 网站生成器怎么做网站建设与管理实训主要内容
  • 网站信用认证可以自己做吗稀奇古怪好玩有用的网站
  • MySQL 基础语句
  • Linux中CPU初始化和调度器初始化函数的实现
  • MATLAB基于ST-CNN-SVM的轴承故障诊断,S变换和卷积神经网络结合支持向量机
  • 在优豆云免费云服务器上初探SSH与SCP的便捷操作
  • MySQL数据库:软件、相关知识和基本操作
  • Bahdanau注意力
  • 重生之我在大学自学鸿蒙开发第七天-《AI语音朗读》
  • Spring AI 1.0 GA 深度解析:Java生态的AI革命已来
  • Linux网络之----TCP网络编程
  • 【零基础学习CAPL语法】——writeLineEx() 函数
  • 计算机网络数据链路层
  • 做网站选什么专业门户网站开发步骤博客
  • 论文写作 24: 全文保持同样的节奏
  • 洛谷 P1438 无聊的数列 题解