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

Android面试指南(九)

目录

1、Android应用启动流程

1.1、Android系统启动流程

1.2、Launcher进程启动流程

1.3、ActivityThread

2、Activity的View树测绘流程

2.1、Activity生命周期方法查找

2.2、WindowManager查找

2.3、ViewRootImpl分析

3、页面刷新机制

4、手势分发来源

1、Android应用启动流程

1.1、Android系统启动流程

整体架构(自下而上):

BootLoader--->Linux Kernel--->(HAL)--->C++ Framework--->Android Framework--->Apps

①、安卓系统启动流程分层如下:

  • Boot Loader层:主板通电后加载引导程序,执行内存检查与硬件初始化。
  • Linux Kernel层:加载相机、显示屏等硬件驱动,通过硬件抽象层(HAL)统一上层访问接口。
  • Init进程:创建首个用户进程,孵化adbd/logd守护进程,并派生Zygote进程。
  • Zygote进程:连接Native与Java世界,在该进程中会调用ZygoteInit.java类,在该类的入口方法中会创建SystemServer进程,后续所有App进程都是由Zygote进程孵化的。App进程创建完成之后,会由ZygoteInit反射调用ActivityThread入口类,从而使APP进程得以启动。
  • SystemServer进程:启动AMS、PMS等系统服务,最终通过systemReady通知AMS启动Launcher应用。

②、ZygoteInit的main方法

ZygoteInit.main方法核心功能包括:

  • 资源预加载:系统Class、资源文件及动态库,提升APP启动速度。
  • 启动SystemServer判断:根据参数决定是否启动系统服务进程。
  • 创建Socket服务:监听AMS的进程创建请求。

③、SystemServer进程

ZygoteInit的main方法中启动SystemServer进程后,其入口类SystemServer.java会创建以下系统服务:

  • 引导服务:AMS、PMS、PackageManagerService等。
  • 核心服务:BatteryService、GPUService等。
  • 其它服务:WindowManagerService、BluetoothService等。

服务类型

示例服务

功能描述

引导服务

ActivityManagerService

四大组件调度(安卓10后由ActivityTaskManagerService接管)

核心服务

BatteryService

电池状态管理

其他服务

WindowManagerService

窗口管理

最终通过systemReady通知AMS启动Launcher应用

1.2、Launcher进程启动流程

①、ActivityManagerService

  • ActivityManagerService通过systemReady方法启动应用,调用ActivityTaskManagerService.startHomeOnAllDisplays方法。

②、ActivityTaskManagerService

  • ActivityTaskManagerService将启动工作委托给RootActivityContainer,后者调用PackageManagerService查询Launcher应用。

③、RootActivityContainer

  • RootActivityContainer.startHomeOnDisplay方法构造Intent.CATEGORY_HOME意图,筛选符合Launcher标准的Activity。

④、ActivityStarter

  • ActivityStarter检查Activity注册状态、类文件存在性及权限,并根据LaunchMode和IntentFlag决定复用或新建Activity。

⑤、ActivityStack

  • ActivityStack.resumeTopActivityLocked暂停当前可见Activity(触发onPause),并判断目标进程是否已启动。

⑥、ActivityStackSupervisor

  • ActivityStackSupervisor.startSpecificActivityLocked进一步检查进程状态,未启动则进入进程创建分支。

补充了解:任务栈模型

类名

作用

关联关系

ActivityRecord

服务端Activity映射

存储在TaskRecord中

TaskRecord

任务栈

包含多个ActivityRecord

ActivityStack

任务栈管理者

管理多个TaskRecord

ActivityStackSupervisor

全局任务栈管理者

管理所有ActivityStack

⑦、ProcessList

  • ProcessList.startProcessLocked配置进程参数(如ABI类型和入口类entryPoint:android.app.ActivityThread),最终由ZygoteProcess处理。

⑧、ZygoteProcessor

  • ZygoteProcess通过Socket连接Zygote进程,传递参数后由ZygoteInit反射执行入口类,完成进程创建。

1.3、ActivityThread

(一)、整体介绍

ActivityThread是安卓应用进程的入口类,其入口方法遵循Java规范定义为public static void main,这是所有Java程序的统一约定。

ActivityThread的结构如下:

关键方法

功能描述

所属类

scheduleReceiver

创建BroadcastReceiver

ApplicationThread

scheduleCreateService

创建Service

ApplicationThread

scheduleBindService

绑定Service服务

ApplicationThread

bindApplication

创建Application对象并执行生命周期

ApplicationThread

scheduleInstallProvider

创建ContentProvider并执行生命周期

ApplicationThread

handleLaunchActivity

启动和创建Activity生命周期

ClientTransactionHandler

架构设计特点:安卓10将Activity生命周期调度方法重构至ClientTransactionHandler抽象类,实现单一职责原则,但实际调用仍通过ActivityThread完成。

(二)、ActivityThread的分析

1)、ActivityThread的main()方法

  • Looper.prepareMainLooper():在主线程初始化消息循环驱动器
  • Looper.loop():启动主线程消息循环,赋予消息分发能力
  • ActivityThread.attach():传入参数system为false,标识当前为非系统应用进程

2)ActivityThread的attach()方法

  • ActivityManager.getService():获取IActivityManager接口实例(实际对应ActivityManagerService对象)
  • attachApplication():向ActivityManagerService注册应用进程,实现四大组件调度能力
  • BinderInternal.addGcWatcher():内存监控机制,当内存占用达阈值时释放非活跃页面

ActivityManagerService的attachApplication方法

①、attachApplicationLocked():核心功能包括:

  • 通过IApplicationThread.bindApplication()触发Application创建流程
  • 启动任务栈顶已注册但未运行的Activity(如Launcher的首个Activity)
  • ActivityThread的handleMessage方法

②、BIND_APPLICATION消息:通过主线程Handler将Application创建任务从子线程切换至主线程执行

  • ActivityThread的handleBindApplication方法

③、makeApplication()

  • 通过LoadedApk类加载APK运行时映射
  • 解析AndroidManifest中application节点定义的类名(未指定时默认使用android.app.Application)
  • mInstrumentation.newApplication():通过AppComponentFactory实例化Application对象

④、attach()

attachBaseContext():Application生命周期中首个被调用的方法(早于onCreate)

ActivityTaskManagerInternal.attachApplication()方法

  • ActivityTaskManagerInternal.attachApplication():
    • 定位任务栈顶Activity(top变量)
    • 通过realStartActivityLocked()启动未关联进程的Activity
  • ClientTransaction机制:
    • LaunchActivityItem:执行Activity启动事务
    • ResumeActivityItem:当top==activity时触发onResume生命周期(状态机设计模式)
  • ClientTransaction的scheduleTransaction方法触发后,会执行LaunchActivityItem的execute方法,进而调用ClientTransactionHandler的handleLaunchActivity方法。
  • handleLaunchActivity方法在ActivityThread中实现,最终通过performLaunchActivity方法创建Activity实例并返回。
  • Activity实例创建过程:先获取ActivityInfo和ComponentName对象,再通过Instrumentation的newActivity方法实例化,最终调用Activity的attach方法和onCreate生命周期。
  • ResumeActivityItem的execute方法同步执行,触发ActivityThread的handleResumeActivity方法,调用performResumeActivity执行onResume生命周期,使界面可见。

ActivityThread还负责BroadcastReceiver、Service、ContentProvider等组件的创建,均通过AppComponentFactory反射实例化。

补充说明状态机设计模式:

安卓10在服务端对Activity生命周期的控制拆分为LaunchActivityItem、TopActivityItem、DestroyActivityItem和PauseActivityItem,这些Item均继承自ActivityLifecycleItem。

状态机设计模式的核心在于对象行为取决于其状态,例如Activity生命周期的调度由具体ActivityLifecycleItem执行,取决于目标生命周期状态。

3)、Activity创建流程总结

  • 应用进程创建入口为ActivityThread的main方法,主要完成两项任务:
    • 初始化Looper并启动主线程消息队列轮询
    • 调用attach方法向AMS注册进程,传递IApplicationThread对象实现跨进程调度
  • AMS通过attachApplication方法触发Application创建,依次执行attachBaseContext和onCreate方法。
  • ActivityTaskManagerService启动任务栈中的Activity,通过ActivityStartSupervisor的realStartActivityLocked方法组装生命周期调度事务:
    • 包含LaunchActivityItem和ResumeActivityItem
    • 通过ClientLifecycleManager的scheduleTransaction执行事务
  • Activity实例化流程:
    • 通过Instrumentation.newActivity反射创建实例
    • 依次调用attach、onCreate和onResume生命周期方法

2、Activity的View树测绘流程

2.1、Activity生命周期方法查找

Q:View的测绘流程入口在哪里?

根据Activity生命周期调用顺序进行分析:attach → onCreate → onStart → onResume

1)、Activity的attach方法

  • 核心操作:
    • 创建PhoneWindow实例(Window的唯一实现类)
    • 处理Fragment相关逻辑(通过FragmentController.dispatchTouch)
    • 接收并赋值方法入参参数
  • 局限:未发现与View测绘相关的关键代码

2)、Activity的onCreate方法

  • 主要流程:
    • 调用setContentView加载布局资源
    • 通过AppCompatDelegate实现布局加载的转发逻辑
  • 关键结论:该方法未直接触发View的测绘流程

3)、AppCompatActivity的setContentView方法

方法步骤

实现细节

关联对象

创建SubDecor

调用ensureSubDecor方法

ContentViewGroup

加载布局

解析传入的布局资源ID

DecorView

视图挂载

将解析后的View添加到contentParent

PhoneWindow

ensureSubDecor方法分析:

  • 逻辑判断:
    • 通过mSubDecorInstalled标志位判断是否已创建SubDecor
    • 未创建时调用createSubDecor方法进行初始化
  • 设计目的:确保DecorView层级结构的完整性

createSubDecor方法分析:

判断条件

执行分支

加载资源

窗口是否有标题

加载R.layout.abc_screen_toolbar

ActionBar

是否为浮动窗口

加载对话框样式布局

Dialog主题

常规Activity

加载R.layout.abc_screen_content

ContentFrameLayout

PhoneWindow的setContentView方法分析:

  • 核心流程:
    • DecorView校验:通过generateDecor创建基础容器
    • ContentParent生成:调用generateLayout根据主题创建内容容器
    • 视图添加:将用户布局添加到contentParent
  • 重要机制:
    • mContentParentExplicitlySet标志位:防止重复调用setContentView后请求窗口特性
    • 主题解析:通过generateLayout处理窗口样式属性

setContentView方法分析:

  • 遗留问题:仍未发现触发View测绘流程的入口代码
  • 分析方向:需继续追踪ActivityThread中的生命周期调用链

4)、Activity的onStart方法

  • 方法特点:实现逻辑简单,未包含View测绘相关代码
  • 调用时机:位于onCreate之后、onResume之前

4)、Activity的onResume方法

  • 关键发现:
    • View测绘触发点:实际位于ActivityThread.handleResumeActivity方法
    • 执行顺序:先执行performResumeActivity,再通过WindowManager添加DecorView
    • 可见性控制:添加View时设置为INVISIBLE,防止软键盘弹出导致页面闪烁
    • 窗口管理:通过WindowManagerImpl实现View的增删改查操作

2.2、WindowManager查找

  • 根据经验,internal相关的实现类通常位于service内部。当无法直接查看接口实现类时,实现类通常以Impl作为后缀命名,例如WindowManager的实现类为WindowManagerImpl。类似地,Context虽非接口但其实现类也遵循此规律,ContextImpl类实现了Context基类。
  • WindowManagerImpl类中对addView、updateView等方法进行了转发操作。转发的设计目的在于集中管理:单个应用可能包含多个页面,每个页面对应独立的WindowManager实例。通过WindowManagerGlobal对象统一处理所有页面的视图操作,这种设计模式实现了入口与出口的收拢,对外仅暴露方法定义。

WindowManagerGlobal的addView方法执行流程如下:

  • 参数校验:对传入的view和display对象进行非空校验
  • 类型校验:必须使用WindowManager.LayoutParams类型参数,否则抛出"IllegalArgumentException: params must be WindowManager.LayoutParams"异常
  • 重复添加校验:检查view是否已被添加,重复添加会触发"IllegalStateException: view has already been added to the window manager"异常
  • 核心实例化:方法内会初始化ViewRootImpl对象

2.3、ViewRootImpl分析

  • ViewRootImpl是视图树的顶层节点,负责关联传递的View并启动测量、布局及绘制流程。
  • ViewRootImpl会将传递的View添加到mViews列表中,并将对应的ViewRootImpl添加到mRoots列表中。
  • WindowManagerGlobal的addView方法中,若流程由setContentView触发,则View为DecorView;若直接调用WindowManager.addView,则View为普通View。

ViewRootImpl功能分类如下:

  • 通过WindowSession接口将当前窗口注册至WindowManagerService。
  • 作为页面视图树的顶层节点,是DecorView的父节点。
  • 利用Choreographer接收垂直同步信号,触发视图的测量、布局及绘制流程。
  • 通过InputEventReceiver接收屏幕输入事件并分发。
  • 利用Choreographer同步信号触发视图动画及重绘。

1)、构造方法

  • 关键字段解析:
    • IWindowSession:Binder接口,用于将窗口注册至WindowManagerService。
    • AttachInfo:记录当前View关联的窗口信息,用于判断View是否已附加至窗口。
    • Choreographer:接收硬件垂直同步信号(如60Hz设备每16.7ms一次),协调UI刷新、输入事件派发及动画更新。
  • 垂直同步信号作用:确保应用层在单帧时间(16.7ms)内完成输入事件处理、UI测量及动画刷新。

2)、setView方法

  • 核心操作:
    • requestLayout:在窗口注册前安排首次视图布局测绘。
    • WindowSession.addToDisplay:通过Binder接口注册窗口至WindowManagerService,并创建InputChannel监听屏幕输入事件。
    • View.assignParent:将当前ViewRootImpl设为View的父节点(非视图树节点,仅实现ViewParent接口)。

3)、requestLayout方法

①、checkThread()

  • 线程检查:默认禁止子线程更新UI,但若ViewRootImpl未创建(如Activity初始化阶段),子线程操作可能生效。
  • 子线程更新UI的限制:涉及requestLayout或postInvalidate的更新可能失效,因最终需通过ViewRootImpl的线程检查。
  • 在onCreate中子线程直接更新TextView文本可以生效,但涉及布局或重绘的操作可能失败。

②、scheduleTraversals()

  • 任务调度机制:
    • 同步过滤:通过mTraversalScheduled标记避免同一帧内重复触发测绘流程。
    • 消息屏障:发送屏障消息使异步消息(如UI测绘任务)优先执行,同步消息暂缓。
    • Choreographer回调:垂直同步信号到达时执行TraversalRunnable,触发performTraversals完成测量、布局及绘制。
  • 消息类型区别:
    • 同步消息:常规Handler消息。
    • 异步消息:标记为async的消息(如UI测绘任务),遇屏障时优先执行。
    • 屏障消息:临时阻塞同步消息,仅允许异步消息通过。

③、doTraversal()

  • 重置mTraversalScheduled标记位为false
  • 移除消息队列中的消息屏障,确保同步消息能够执行

④、performTraversals()

  • performTraversals方法作用:根据当前页面View树判断是否需要重新测绘、布局或绘制
    • 关键方法:
      • performMeasure:调用DecorView.measure进行大小测量
      • performLayout:调用DecorView.layout完成页面布局
      • performDraw:通过softwareDraw触发DecorView.draw实现绘制
  • 测量、布局、绘制的源头均来自ViewRootImpl的对应方法

⑤、总结

  • 流程起点:ActivityThread.handleResumeActivity触发WindowManager.addView
  • 核心步骤:
    • WindowManagerGlobal实例化ViewRootImpl并绑定DecorView
    • setView调用requestLayout,通过线程检查后注册垂直同步监听
  • 三大流程执行:
    • performTraversals依次调用measure、layout、draw
    • ViewGroup递归处理子视图的测量、布局和绘制

3、页面刷新机制

Choreographer类用于协调页面的动画、屏幕输入和绘制事件的执行顺序,还包括过滤同一帧内的重复请求(如多次调用requestLayout),避免不必要的重复计算。Choreographer通过接收垂直同步信号(VSync)的时间脉冲,安排下一帧的绘制工作。

1)、Choreographer的构造函数

  • FrameDisplayEventReceiver:向Native层注册监听并接收VSync信号回调的类,信号到达时触发onVsync方法。
  • CallbackQueues:数组结构,每个元素为CallbackQueue队列,对应不同事件类型(如CALLBACK_TRAVERSAL用于View树重绘、CALLBACK_ANIMATION用于动画更新、CALLBACK_INPUT用于输入事件派发)。

2)、CallbackQueue模型

CallbackQueue的数据结构为数组+单链表模型:

  • 每个队列存储CallbackRecord对象,通过addCallbackLocked方法将新请求封装为CallbackRecord并追加至队尾。
  • 优先级设计:不同事件类型(如输入、动画、重绘)通过独立队列管理,确保执行顺序可控。

3)、Choreographer的方法

Choreographer对外暴露两个API:

  • postFrameCallback:立即注册VSync信号监听。
  • postFrameCallbackDelayed:支持延迟注册,参数delayMillis控制延迟时间。两者最终均调用内部方法postCallbackDelayedInternal,默认事件类型为CALLBACK_ANIMATION。

①、postCallbackDelayedInternal方法:

  • 根据callbackType从CallbackQueues中获取对应队列。
  • 封装参数为CallbackRecord并插入队尾。
  • 根据delayMillis决定立即执行scheduleFrameLocked或通过Handler延迟调度。

②、scheduleFrameLocked方法:

  • 检查线程一致性:确保调用线程与创建Choreographer对象的线程相同。
  • 通过FrameDisplayEventReceiver.scheduleVsync订阅VSync信号。

③、scheduleVsyncLocked方法:

scheduleVsyncLocked方法向系统订阅VSync信号,信号到达时触发FrameDisplayEventReceiver.onVsync,最终通过Handler派发异步消息执行doFrame。

④、doFrame方法:

  • doFrame方法核心逻辑:
  • 掉帧检测:计算信号到达与执行的时差,若超过16.7ms(1帧时间)则判定为掉帧,超过30帧输出警告日志。
  • 事件派发:按优先级依次处理CALLBACK_INPUT(输入事件)、CALLBACK_ANIMATION(动画)、CALLBACK_TRAVERSAL(重绘)。

4、手势分发来源

手势接收位于Window.InputEventReceiver中,事件派发至Activity前需经过该组件处理。

1)、手势分发

  • 事件入口:onInputEvent方法接收InputEvent参数,该参数可能包含屏幕点击或键盘事件。
  • 事件封装:方法内部调用enqueueInputEvent,将事件封装为QueuedInputEvent对象并添加至队列尾部。
  • 事件派发:通过doProcessInputEvents方法从队列头部依次派发事件,调用deliverInputEvent处理。
  • 处理阶段:输入事件需经过多个预处理阶段:
    • ViewPostImeInput:处理屏幕点击事件。
    • ImeInputStage:处理键盘事件。
    • 责任链模式:各阶段按优先级依次处理事件(NativePreImeInputStage→ViewPreImeInputStage→ImeInputStage→EarlyPostImeInputStage→NativePostImeInputStage→SyntheticInputStage),未处理则传递至下一阶段。
  • 点击事件判定:若事件类型为InputDevice.SOURCE_CLASS_POINTER,则进入processPointerEvent方法,最终调用View.dispatchPointerEvent。
  • 事件转发路径:
    • View.dispatchTouchEvent转发至DecorView。
    • DecorView通过Window.Callback接口将事件传递至Activity.dispatchTouchEvent。
    • Activity将事件转发至PhoneWindow.superDispatchTouchEvent,最终交由ViewGroup.dispatchTouchEvent处理。

2)、手势分发流程总结

  • 事件监听注册:通过ViewRootImpl.WindowInputEventReceiver监听系统输入事件。
  • 预处理阶段:事件需经过责任链模式的多个阶段校验。
  • Activity介入:事件通过Window.Callback接口转发至Activity,便于开发者拦截或自定义手势逻辑。
  • 最终分发:PhoneWindow将事件传递至DecorView,最终由ViewGroup处理。

OK,今天的内容就到这里吧,下期再会!


文章转载自:

http://ug9AL56I.fpkpz.cn
http://OX32jeA1.fpkpz.cn
http://q6pbevs3.fpkpz.cn
http://cpsln2zP.fpkpz.cn
http://fIKosbJc.fpkpz.cn
http://rb04jxay.fpkpz.cn
http://r3C0ywWA.fpkpz.cn
http://PtU8xnjr.fpkpz.cn
http://gdnjaBU5.fpkpz.cn
http://m0HJVfFD.fpkpz.cn
http://p7FB2MnN.fpkpz.cn
http://C5qqqaoA.fpkpz.cn
http://Wro3sRtZ.fpkpz.cn
http://eOZTWwCO.fpkpz.cn
http://s2lgl6Lv.fpkpz.cn
http://sLlobXoj.fpkpz.cn
http://iMMugTdi.fpkpz.cn
http://qWjv6qFV.fpkpz.cn
http://zxOdfouZ.fpkpz.cn
http://196R1rt2.fpkpz.cn
http://gWPfADFC.fpkpz.cn
http://ubTXlz3H.fpkpz.cn
http://1GQ2UvYy.fpkpz.cn
http://v3tA8y2q.fpkpz.cn
http://OmB8BNT9.fpkpz.cn
http://ig2Ng5cC.fpkpz.cn
http://9VcByyyi.fpkpz.cn
http://oNGKjsyS.fpkpz.cn
http://YCryvcZt.fpkpz.cn
http://CKhGn62R.fpkpz.cn
http://www.dtcms.com/a/381320.html

相关文章:

  • Halcon编程指南:符号与元组操作详解
  • 嵌入式第五十二天(GIC,协处理器,异常向量表)
  • 嵌入式学习day48-硬件-imx6ul-key、中断
  • 查找算法和递推算法
  • Webman 微服务集成 RustFS 分布式对象存储
  • 基于51单片机的太阳能锂电池充电路灯
  • 【人工智能通识专栏】第十三讲:图像处理
  • 滚动分页查询-通俗解释
  • 电缆工程量计算-批量测量更轻松
  • UDS NRC速查
  • L2-【英音】地道语音语调--语调
  • 13.渗透-.Linux基础命令(五)-用户管理(修改用户密码)
  • 解决串口数据乱序问题
  • 智能化集成系统(IBMS):构建智慧建筑 “中枢大脑” 的全方案
  • 基于游标(Cursor)的方式来实现滚动分页
  • 30.线程的互斥与同步(四)
  • 《没有架构图?用 netstat、ss、tcpdump 还原服务连接与数据流向》
  • 仓颉语言编程入门:第一个 Windows 下的仓颉应用程序
  • 台达A2E
  • 【操作系统核心考点】进程调度算法全面总结:高频题型与易错点解析
  • ethercat在线调试工具
  • python base core partment-day07-异常、模块、包(对零基础小白友好)
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘vaex’问题
  • Acrobat JavaScript 代码中的颜色
  • TCGA单癌肿按单基因高低分组的转录组差异热图分析作图教程
  • SSRF:CVE-2021-40438
  • 传统项目管理与敏捷的核心差异
  • count down 98 days
  • 算法题 Day6---String类(3)
  • 知识模型中优化和模拟决策内容有哪些