本系列为小说《逆袭西二旗》的技术讲解,用于详细说明剧情里涉及的开发细节。

自 2008 年 9 月 23 日发布以来,Android 经历了巨大的演进。多年来,Android SDK 和整个生态发生了显著变化,新工具和解决方案层出不穷,比如 Android Architecture Components(AAC)、Jetpack 系列库,以及 Jetpack Compose。然而,尽管技术不断革新,Android 底层的一些核心机制------如 Intent、Window 和基础 View 架构------却始终保持高度稳定。
不同公司在构建 Android 应用时采用的技术栈和开发方式各不相同。因此,要想找到心仪的 Android 方面工作,必须根据职位描述中的最低要求,以及目标公司实际使用的技术,有针对性地准备面试。了解他们的技术需求,能让你更高效地聚焦重点。
面试题的难度因公司和面试官而异。与其死记硬背答案,不如深入理解底层概念,并多加实践应用。本系列中的问题旨在为你准备 Android 技术面试提供参考,并非涵盖所有可能考题的"标准答案手册"。
有些公司会侧重考察 Android 系统底层运作和架构,以评估你对 Android 基础的理解;另一些则更关注高层 API 或流行库的使用,看你能否快速将其整合进产品中。不同公司的评分标准也大相径庭,这意味着很多问题并没有唯一"完美"的答案。该系列提供的回答只是起点,鼓励你在此基础上进一步拓展和深挖。
本系列无意覆盖 Android 开发这一广阔领域中的所有可能问题,而是希望为你打下扎实基础,助你高效准备,并根据目标岗位的具体要求调整学习方向。需要特别说明的是,本系列并未深入探讨高级第三方库或底层硬件相关功能(如 Camera API、Bluetooth 等)。如果这些内容与你的职业目标相关,你需要额外查阅资料,自主补充知识。
祝你在 Android 面试准备中一切顺利!
Android 分层是什么
Android 是一个开源操作系统,主要面向智能手机和平板等移动设备。它由 Google 开发并维护,基于 Linux 内核,提供了一个强大而灵活的平台,能够适配各种硬件配置和设备。
面试问题
Android 的平台架构由多个层级组成,包括 Linux 内核、Android 运行时(ART)以及硬件抽象层(HAL)。你能解释一下这些组件是如何协同工作,以确保应用顺利运行并与硬件交互的吗?
关键特性
- 开源且高度可定制:Android 是开源的(即 Android 开源项目,AOSP),开发者和厂商可以根据自身需求自由修改和定制系统。这种灵活性推动了它在各类设备上的广泛应用与创新,包括智能穿戴设备、电视乃至物联网(IoT)设备。
- 基于 SDK 的应用开发:Android 应用主要使用 Java 或 Kotlin 编写,并配合 Android 软件开发工具包(SDK)。开发者可通过 Android Studio 等工具,在平台上完成应用的设计、开发与调试。
- 丰富的应用生态:Google Play 商店是 Android 官方的应用分发平台,提供数百万款涵盖游戏、生产力工具等各类别的应用。开发者也可通过第三方应用商店或直接提供 APK 文件进行独立分发。
- 多任务处理与资源管理:Android 支持多任务运行,用户可同时开启多个应用。系统采用托管式内存管理和高效的垃圾回收机制,在不同设备上优化性能表现。
- 广泛的硬件兼容性:Android 覆盖从入门级到高端旗舰的各类设备,对不同屏幕尺寸、分辨率及硬件配置均有出色的适配能力。
Android 系统架构
Android 平台架构采用模块化分层设计,由多个组件构成:

相信 Android 开发再熟悉不过这张图了!
那我们从下往上依次说明这些层:
- 电源管理:Linux 内核中的电源子系统,负责直接控制 CPU、设备和整机的休眠、唤醒与功耗状态,为上层省电机制提供硬件级支持。
- Linux 内核:Linux 内核构成了 Android 操作系统的基础,负责硬件抽象,确保软件与硬件之间的无缝交互。其核心职责包括内存与进程管理、安全策略执行,以及管理 Wi-Fi、蓝牙、显示等硬件组件的驱动程序。
- 硬件抽象层(HAL) :硬件抽象层(HAL)提供了一组标准接口,将 Android 的 Java API 框架与设备硬件连接起来。它由多个库模块组成,每个模块针对特定硬件(如摄像头或蓝牙)进行定制。当框架 API 请求访问硬件时,Android 系统会动态加载对应的 HAL 模块来完成请求。
- Android 运行时(ART)与核心库:Android 运行时(ART)负责执行由 Kotlin 或 Java 编译而来的字节码。ART 支持"提前编译"(AOT)和"即时编译"(JIT),以优化应用性能。核心库则提供了数据结构、文件操作、多线程等关键功能的 API,为应用开发构建了完整的运行环境。
- 原生 C/C++ 库 :Android 包含一系列用 C 和 C++ 编写的原生库,用于支撑关键功能。例如,OpenGL 负责图形渲染,SQLite 提供数据库操作能力,WebKit 用于网页内容展示。这些库既被 Android 框架内部使用,也可被应用直接调用,以处理对性能要求较高的任务。
- Android 框架(API) :应用框架层提供了面向开发者的高层服务和 API,包括
ActivityManager、NotificationManager、ContentProvider等,让开发者能够高效构建 Android 应用,并充分利用系统能力。 - 应用程序:最上层是所有面向用户的应用,包括系统自带应用(如通讯录、设置)和基于 Android SDK 开发的第三方应用。这些应用依赖底层各模块,将功能顺畅地交付给用户。
总结
Android 是全球使用最广泛的移动操作系统,占据着绝对的市场份额。它不仅推动创新,还为开发者提供了触达数十亿用户的机会。凭借其高度的适应性和开源特性,Android 得以在各种市场中蓬勃发展,并成为众多非手机设备的基石。
Intent 是什么

Intent 是对即将执行操作的一种抽象描述。它作为一种消息对象,让 Activity、Service 和 BroadcastReceiver 能够彼此通信。Intent 通常用于启动一个 Activity、发送广播或启动一个 Service,还能在组件之间传递数据,是 Android 基于组件架构的核心机制之一。
Android 中主要有两种 Intent:显式 Intent 和隐式 Intent。
面试问题
显式 Intent 和隐式 Intent 的核心区别是什么?各自适用于哪些场景?
Android 系统如何决定由哪个应用来处理一个隐式 Intent?如果找不到合适的应用,又会发生什么?
显式 Intent
定义 :显式 Intent 通过直接指定组件名称,明确指出要启动的具体组件(Activity 或 Service)。
使用场景 :当你明确知道目标组件时使用显式 Intent,例如启动自己应用内的某个特定 Activity。
示例场景 :如果你在同一个应用内从一个 Activity 跳转到另一个 Activity,就应该使用显式 Intent。
你可以像下面这样使用显式 Intent:
Kotlin
val intent = Intent(this, TargetActivity::class.java)
startActivity(intent)
隐式 Intent
定义 :隐式 Intent 不指定具体组件,而是声明一个通用的操作意图。系统会根据该 Intent 中的动作(action)、类别(category)和数据(data),自动匹配能够处理它的组件。
使用场景 :当你希望执行一个可由其他应用或系统组件处理的操作时,隐式 Intent 非常有用,比如打开一个网页链接或分享内容。
示例场景 :如果你要通过浏览器打开一个网页,或者把内容分享给其他应用,就应该使用隐式 Intent。此时,系统会决定由哪个应用来处理这个请求。
你可以像下面这样使用隐式 Intent:
Kotlin
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.example.com")
startActivity(intent)
如果使用隐式 Intent 启动 Activity,但系统中没有应用能处理该 Intent,会抛出 ActivityNotFoundException。
正确做法是,在调用 startActivity() 之前,应使用 PackageManager 检查是否存在可处理的 Activity:
Kotlin
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, "Hello")
}
// 检查是否有应用能处理
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent)
} else {
// 提示用户或降级处理
Toast.makeText(this, "没有应用可以处理此操作", Toast.LENGTH_SHORT).show()
}
总结
显式 Intent 用于应用内部导航,目标组件是明确已知的。
而隐式 Intent 则用于那些可能由外部应用或其他组件处理的操作,无需直接指定目标。它更像一种向系统提需求的工作方式,这让 Android 生态更具灵活性,也让应用之间能无缝协作。
进阶:什么是 IntentFilter
Android 中的 IntentFilter 用于定义应用组件如何响应特定的 Intent,比如打开一个链接或处理一条广播。它本质上是一种过滤器,用来声明某个 Activity、Service 或 BroadcastReceiver 能够处理哪些类型的 Intent,这些声明写在 AndroidManifest.xml 文件中。
每个 IntentFilter 可以包含 Action、Category 和数据类型,以便精准匹配传入的 Intent。合理地定义 IntentFilter,能让你的应用与其他应用及系统组件无缝协作,从而提升整体功能体验。
当发送一个隐式 Intent 时,Android 系统会根据该 Intent 的属性,与已安装应用的清单文件中声明的 IntentFilter 进行匹配,从而确定应启动哪个组件。如果找到匹配项,系统就会启动对应的组件,并将 Intent 对象传递给它。如果多个组件都能匹配该 Intent,系统会弹出一个选择器对话框,让用户自行决定使用哪个应用来处理该操作。

PendingIntent 又是什么
PendingIntent 是一种特殊的 Intent,它授权其他应用或系统组件在未来某个时刻,以你应用的名义执行一个预先定义好的 Intent。这种机制特别适用于那些需要在你的应用生命周期之外触发的操作,比如发送通知或与后台服务交互。
面试问题
什么是 PendingIntent?它和普通 Intent 有什么区别?
能否举一个必须使用 PendingIntent 的场景?
核心特性
PendingIntent 本质上是对普通 Intent 的一层封装,能让这个 Intent 在你的应用生命周期结束后依然有效。它把执行 Intent 的权限委托给其他应用或系统服务,并且这些组件会以你应用的身份和权限来执行操作。PendingIntent 可用于 Activity、Service 或 BroadcastReceiver。
它主要有三种形式:
- Activity:启动一个 Activity。
- Service:启动一个 Service。
- Broadcast:发送一条广播。
你可以通过 PendingIntent.getActivity()、PendingIntent.getService() 或 PendingIntent.getBroadcast() 等工厂方法来创建对应的 PendingIntent。
Kotlin
// 1. 创建 Intent 跳转到目标 Activity
val intent = Intent(this, MyActivity::class.java)
// 2. 创建 PendingIntent,用于通知点击后启动 Activity
val pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT // 更新现有 PendingIntent
)
// 3. 构建通知
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Title")
.setContentText("Content")
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent) // 点击通知时触发
.build()
// 4. 发送通知
NotificationManagerCompat.from(this).notify(NOTIFICATION_ID, notification)
PendingIntent 支持多种标志(flag),用于控制其行为以及与系统或其他组件的交互方式:
FLAG_UPDATE_CURRENT:用新数据更新已存在的PendingIntent。FLAG_CANCEL_CURRENT:在创建新的PendingIntent前,先取消已存在的实例。FLAG_IMMUTABLE:将PendingIntent设为不可变,防止接收方修改其内容。FLAG_ONE_SHOT:确保该PendingIntent只能使用一次。
使用场景
- 通知(Notifications) :用户点击通知时,可触发打开某个
Activity等操作。 - 闹钟(Alarms) :配合
AlarmManager调度定时任务。 - 服务(Services) :将任务委托给
ForegroundService或BroadcastReceiver,用于执行后台操作。
安全事项
始终为 PendingIntent 设置 FLAG_IMMUTABLE,以防止恶意应用篡改其内部的 Intent。这一点从 Android 12(API 级别 31)开始尤为重要------在某些场景下,系统已强制要求必须使用该标志。
总结
PendingIntent 是 Android 中的一项核心机制,即使你的应用未在前台运行,也能实现与系统组件或其他应用之间的无缝通信。通过合理管理标志(flags)和权限,你可以确保延迟任务的安全、高效执行。
Serializable 和 Parcelable 有什么区别

在 Android 中,Serializable 和 Parcelable 都是用来在不同组件(如 Activity 或 Fragment)之间传递数据的机制,但它们在性能和实现方式上有明显区别。
面试问题
在 Android 中,Serializable 和 Parcelable 有哪些关键区别?为什么在组件间传递数据时通常更推荐使用 Parcelable?
Serializable
Java 标准接口 :Serializable 是 Java 提供的标准接口,用于将对象转换为字节流,以便在 Activity 之间传递或写入磁盘。
基于反射:它依赖 Java 反射机制,在运行时动态检查类及其字段来完成序列化。
性能 :相比 Parcelable,Serializable 更慢,因为反射本身开销较大。此外,序列化过程中会产生大量临时对象,增加内存负担。
适用场景 :当性能不是关键因素,或在非 Android 特有的代码库中使用时,Serializable 是一个可行的选择。
Parcelable
Android 专属接口 :Parcelable 是 Android 特有的接口,专为在 Android 组件间实现高性能的进程间通信(IPC)而设计。
性能 :Parcelable 比 Serializable 更快,因为它针对 Android 做了优化,不依赖反射机制,并且通过避免创建大量临时对象来减少垃圾回收的压力。
适用场景 :在 Android 中传递数据时,尤其是涉及 IPC 或在 Activity、Service 之间传输数据且对性能有要求的场景下,推荐使用 Parcelable。
在现代 Android 开发中,kotlin-parcelize 插件通过自动生成实现代码,大幅简化了创建 Parcelable 对象的过程。相比早期需要手动编写的方式,这种方法更加高效。只需在类上添加 @Parcelize 注解,插件便会自动生成所需的 Parcelable 实现。下面是一个示例,展示其工作方式:
Kotlin
import kotlinx.parcelize.Parcelize
import android.os.Parcelable
@Parcelize
class User(val firstName: String, val lastName: String, val age: Int) : Parcelable
通过这样的设置,你不再需要手动重写 writeToParcel 方法或实现 CREATOR,大幅减少了样板代码,提升了可读性。
如果你的类使用了
@Parcelize注解,但其中包含了一个既不是基本类型、又未被@Parcelize标记的属性,就会遇到如下错误:
Type is not directly supported by 'Parcelize'. Annotate the parameter type with '@RawValue' if you want it to be serialized using 'writeValue()'.这是因为
Parcelize编译器插件在序列化时会尝试"展开"所有属性,而任何不支持或无法识别的类型都必须显式标记。为避免这个问题,请确保所有复杂类型或自定义类型要么自身已正确实现
Parcelable,要么用@RawValue注解标注,以表明你希望它们通过writeValue()进行手动序列化。
关键区别
| 特性 | Serializable | Parcelable |
|---|---|---|
| 类型 | 标准Java接口 | Android专用接口 |
| 性能 | 较慢,使用反射 | 更快,针对Android优化 |
| 垃圾创建 | 产生更多垃圾(更多对象) | 产生较少垃圾(高效) |
| 使用场景 | 适用于通用Java使用 | 推荐用于Android,尤其是IPC |
总结
一般来说,在 Android 应用中,优先选择 Parcelable,因为它在大多数使用场景下性能更优。
- 在简单场景、非性能敏感的操作,或处理与 Android 无关的通用 Java 代码时,可以使用
Serializable。 - 而在涉及 Android 特有组件且对性能有要求的场景下(例如进程间通信 IPC),应优先使用
Parcelable,因为它针对 Android 的 IPC 机制做了高度优化,效率高得多。
进阶:Parcel 与 Parcelable
Parcel 是 Android 中的一个容器类,用于在应用的不同组件(如 Activity、Service 或 BroadcastReceiver)之间实现高性能的进程间通信。它的核心作用是对数据进行序列化(marshaling,即"扁平化")和反序列化(unmarshaling,即"还原"),以便跨越 Android 的 IPC 边界传递。
Parcel 不仅可以传输扁平化的数据,还能携带指向活跃 IBinder 对象的引用,通过 IPC 机制进行传递。它专为高性能 IPC 传输而设计,配合 Parcelable 接口,能让对象高效地序列化并在组件间流转。
需要注意的是,Parcel 并非通用的序列化工具,也不应用于持久化存储------因为其底层实现可能随系统版本变化,导致旧数据无法读取。
Parcel 提供了丰富的 API,支持读写基本数据类型、数组以及 Parcelable 对象,使对象能够自行序列化并在需要时重建。此外,它还提供了一些优化方法:在处理 Parcelable 对象时,可省略写入类信息,但要求接收方提前知道数据类型,从而提升传输效率。
Parcelable 是 Android 特有的接口,用于将对象序列化以便通过 Parcel 传递。实现了 Parcelable 的对象可以被写入 Parcel,并从中恢复,因此非常适合在 Android 组件之间传递复杂数据。