互联网大厂 Android 面试题大全与核心知识点解析
前言
在技术面试中,基础知识的扎实程度往往决定了候选人的上限。本文整理了 Java、Android 系统原理、Flutter 框架及性能优化等高频考点,旨在帮助开发者梳理知识体系,提升面试通过率。
一、Java 基础与异常机制
1. Java 异常机制中,Exception 与 Error 的区别
在 Java 中存在一个 Throwable 可抛出类,它有两个重要的子类:Error 和 Exception。
- Error:表示程序中较严重的错误,通常是程序无法处理的。例如 JVM 运行错误(
VirtualMachineError),当 JVM 不再有继续执行操作所需的内存资源时,会出现OutOfMemoryError。这些错误发生时,JVM 一般会选择终止线程。它们是不可查的,不在程序的控制和处理能力之外,绝大多数是程序运行时不允许出现的状况。 - Exception:表示程序可以处理的异常。分为运行时异常(
RuntimeException)与非运行时异常。
运行时异常 (RuntimeException)
又称不受检查异常。Java 编译检查时不会提示,需要在运行时暴露出来。例如:
- 下标越界 (
ArrayIndexOutOfBoundsException) - 空指针异常 (
NullPointerException)
非运行时异常 (Checked Exception)
RuntimeException 之外的异常统称为非运行时异常,如 IOException、SQLException。这是检查异常,必须进行显式处理(throw 到上层或 try-catch),否则程序不能编译通过。
2. Java 集合框架与并发编程
- HashMap 原理:基于数组 + 链表 + 红黑树。JDK 1.8 后,当链表长度超过 8 且数组长度超过 64 时,链表转为红黑树,提高查询效率至 O(log n)。
- ConcurrentHashMap:JDK 1.7 使用分段锁,JDK 1.8 使用 CAS + synchronized 保证线程安全,性能更高。
- ThreadLocal:用于实现线程隔离,每个线程拥有独立的变量副本,常用于存储用户上下文或数据库连接。
二、Android 核心机制
3. Activity.runOnUiThread 的理解
该方法用于将任务绑定到主线程执行。源码逻辑如下:
- 判断当前线程是否为主线程,如果是则直接执行 Runnable。
- 如果不是,通过默认构造函数创建的 Handler(绑定主线程 Looper)将 Runnable post 到 MessageQueue 中等待处理。
public void runOnUiThread(Runnable action) {
if (Thread.currentThread() == mUiThread) {
action.run();
} else {
mHandler.post(action);
}
}
4. 子线程能否更新 UI?为什么?
原则上不能直接更新。UI 绘制过程需要保持同步,主线程负责绘制 UI。如果在子线程直接修改 View,可能导致页面闪烁或不流畅。
例外情况:在 Activity 的 onResume() 之前(即 onCreate, onStart, onResume 阶段),主线程的绘制尚未开始,此时子线程理论上可以更新 UI,但强烈不建议这样做,应统一使用 Handler 或 RunOnUIThread 机制。
5. Handler 机制和原理
Handler 机制是 Android 跨线程通信的核心,包含四个组件:Handler、MessageQueue、Looper、Message。
- 创建:在 UI 线程创建 Handler 实例,重写
handleMessage方法处理消息。 - 发送:子线程创建 Message 对象,设置数据(arg1, arg2, obj 等),调用
handler.sendMessage(msg)。 - 入队:Message 被放入 MessageQueue 中等待。
- 轮询:Looper 不断从 MessageQueue 取出消息,调用
dispatchMessage传递给 Handler。 - 处理:Handler 调用
handleMessage执行具体逻辑。
Looper 的存在与线程独有性
- Looper 实例管理在静态属性
sThreadLocal中。 - ThreadLocal 内部通过 ThreadLocalMap 持有 Looper,key 为 ThreadLocal 实例本身,value 为 Looper。
- 每个 Thread 有自己的 ThreadLocalMap,保证每个线程对应一个独立的 Looper 实例。
- 一个 App 通常只有一个主线程 Looper,其他线程需手动调用
Looper.prepare()和Looper.loop()。
6. ActivityManagerService (AMS) 是什么?
- 职责:负责系统中四大组件的启动、切换、调度及应用进程的管理和调度。类似于操作系统中的进程管理模块。
- 初始化时机:在 SystemServer 进程开启时初始化。
- 作用:打开 App 时,AMS 通知 Zygote 进程创建应用进程,并控制所有 Activity 的生命周期。
三、Binder 与 IPC 通信
7. Zygote 为什么不采用 Binder 机制进行 IPC?
Zygote 进程在 fork() 前主动停止了其他线程,fork() 后重新启动。如果 Zygote 采用 Binder 机制,由于 Binder 依赖线程池,会涉及 fork() 与多线程的问题(子进程继承父进程线程可能导致状态不一致)。虽然严格来说 Binder 不一定非要多线程,但为了稳定性,Zygote 采用了 Socket 通信。
8. Binder 的优势
性能方面
- 共享内存:0 次数据拷贝。
- Binder:1 次数据拷贝。
- Socket/管道:2 次数据拷贝。
稳定性方面
- Binder 基于 C/S 架构,客户端与服务端职责明确,相互独立,稳定性优于共享内存。
安全性方面
- 传统 IPC 无安全措施,依赖上层协议,UID/PID 易被伪造。
- Binder 支持实名 Binder 和匿名 Binder,内核层校验 UID/PID,安全性高。
9. Binder 如何实现一次拷贝
Linux 使用虚拟内存寻址方式:
- 用户空间虚拟内存映射到物理内存。
- 读写虚拟内存即读写物理内存(内存映射)。
- 通过系统调用
mmap()实现。 - Binder 在内核空间接收方用户控件的数据缓存区之间建立一层内存映射,相当于直接将数据映射到接收方用户空间,减少了一次数据拷贝。
四、View 系统与 Flutter 架构
10. Widget、Element 和 RenderObject 的关系
- Widget:不可变配置对象,描述 UI 结构。
- Element:Widget 在视图树中的实例,负责维护状态和生命周期。
- RenderObject:负责布局和绘制的底层对象。
关系:Widget 和 Element 是一对一关系。每个 Widget 的 context 都是独一无二的。Element 树遍历后根据类型变化重建 RenderObject。增加 Widget 后,若类型改变,对应 Element 会重建 RenderObject。
11. Flutter 是什么?
Flutter 是谷歌的移动 UI 框架,可快速构建高质量原生用户界面。支持 iOS 和 Android,可与现有代码共存。完全免费、开源。
12. Flutter 特性
- 快速开发:毫秒级热重载。
- 绚丽 UI:内建 Material Design 和 Cupertino Widget,支持丰富动画。
- 响应式:Reactive 模型,灵活 API 解决 2D、手势难题。
- 原生访问:通过 Platform Channel 调用原生功能。
- 高性能:自绘引擎 Skia/Impeller,媲美原生性能。
13. Flutter 生命周期
- initState():State 与 BuildContext 关联,但 Context 未完全装载。获取 Context 需用
Future.delayed。 - didChangeDependencies():initState 之后调用,依赖关系变化时触发。
- deactivate():State 暂时从视图树移除时调用,页面切换时触发。
- dispose():Widget 销毁前调用,先于 deactivate。
- didUpdateWidget:Widget 状态变化时调用。
14. Stream 订阅模式
- 单订阅 (Single):只能有一个订阅者。订阅者出现前持有数据,出现后转发。类似点对点。
- 多订阅 (Broadcast):多个订阅者。数据发布时传递给所有订阅者。类似发布订阅。
- 转换:通过
Stream.asBroadcastStream()可将单订阅转为多订阅。
15. Dart 线程模型
- 以事件循环和消息队列形式存在。
- 两个任务队列:Microtask(内部,优先级高)和 Event(外部)。
- Microtask 过多会阻塞 Event 队列,导致触摸、绘制卡顿。
- 四大线程:UI Runner、GPU Runner、IO Runner、Platform Runner(原生主线程)。
- 异步操作:通过 Isolate 或 compute 执行真正的跨线程操作。
五、进阶优化与常见问题
16. 内存泄漏检测与优化
- 常见原因:静态引用 Context、未注销监听器、单例持有 Activity 等。
- 工具:MAT (Memory Analyzer Tool)、LeakCanary。
- 优化:弱引用 Context、及时取消回调、避免长生命周期对象持有短生命周期对象。
17. 网络请求优化
- OkHttp 连接池:复用 TCP 连接,减少握手开销。
- Gzip 压缩:减少传输数据量。
- 图片加载:使用 Glide 或 Picasso 进行缓存和缩放。
- HTTPS:强制使用 HTTPS 保障数据安全。
18. 数据库设计原则
- Room 持久化库:基于 SQLite 的抽象层,提供编译时检查。
- 索引优化:对常用查询字段建立索引。
- 事务管理:确保数据一致性,避免部分写入失败。
结语
面试不仅是技术的考察,更是逻辑思维与沟通能力的体现。建议求职者深入理解原理,结合项目经验作答,保持自信与谦逊。无论结果如何,每一次面试都是宝贵的成长机会。


