Android 中大厂秋招常见面试题及答案解析
Android 开发中大厂秋招的常见面试题,涵盖 Java 基础、Android 核心机制、Framework 原理及 Flutter 框架知识。内容涉及抽象类与接口区别、线程状态管理、Handler 消息机制、Binder 跨进程通信、Zygote 启动流程等关键技术点,并提供了详细的解析与代码示例,旨在帮助求职者系统复习核心技术栈,提升面试通过率。

Android 开发中大厂秋招的常见面试题,涵盖 Java 基础、Android 核心机制、Framework 原理及 Flutter 框架知识。内容涉及抽象类与接口区别、线程状态管理、Handler 消息机制、Binder 跨进程通信、Zygote 启动流程等关键技术点,并提供了详细的解析与代码示例,旨在帮助求职者系统复习核心技术栈,提升面试通过率。

在 Java 面向对象编程中,抽象类和接口都是实现代码复用和约束的重要手段,但设计目的和使用场景有所不同。
主要区别如下:
// 示例:抽象类
abstract class Animal {
String name;
public abstract void eat();
public void sleep() { System.out.println("Sleeping..."); }
}
// 示例:接口
interface Flyable {
void fly();
}
这是 Java 集合框架的核心部分,理解它们的特性对面试至关重要。
Java 线程生命周期包含以下五种状态,对应 Thread.State 枚举:
多线程同步和异步不是一回事。常见的同步机制包括:
在现代 Android 开发中,推荐使用 ViewModel 进行数据管理。
// ViewModel 示例
class SharedViewModel : ViewModel() {
val data = MutableLiveData<String>()
}
子线程是不能直接更新 UI 的。
注意这句话,是不能直接更新,不是不能更新(极端情况下可更新)。绘制过程要保持同步(否则页面不流畅),而我们的主线程负责绘制 ui。极端情况就是,在 Activity 的 onResume(含)之前的生命周期中子线程都可以进行更新 ui,也就是 onCreate, onStart 和 onResume,此时主线程的绘制还没开始。
但在常规开发中,必须通过 Handler、post、runOnUiThread 等方式在主线程更新 UI,否则会导致 CalledFromWrongThreadException。
Handler 机制是 Android 处理异步消息的核心,涉及四个核心组件:Handler、MessageQueue、Looper、Message。
核心流程:Handler.sendMessage -> MessageQueue.enqueueMessage -> Looper.loop() -> MessageQueue.next() -> Handler.dispatchMessage -> Handler.handleMessage。
Android 事件分发机制遵循从父到子,再由子到父的原则。
Android 系统启动是一个复杂的过程,主要步骤如下:
在 POSIX 标准中,fork 的行为是这样的:复制整个用户空间的数据 (通常使用 copy-on-write 的策略,所以可以实现的速度快)以及所有系统对象,然后仅复制当前线程到子进程。
这里有一个关键点:所有父进程中别的线程,到了子进程中都是突然蒸发掉的。对于锁来说,从 OS 看,每个锁有一个所有者,即最后一次 lock 它的线程。
假设这么一个环境,在 fork 之前,有一个子线程 lock 了某个锁,获得了对锁的所有权。fork 以后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主人,所以没有任何人可以对它解锁。当子进程想 lock 这个锁时,不再有任何手段可以解开了,从而导致死锁。
Binder 机制中存在 Binder 线程池,是多线程的。如果 Zygote 采用 Binder 的话就存在上面说的 fork() 与多线程的问题了。
其实严格来说,Binder 机制不一定要多线程,所谓的 Binder 线程只不过是在循环读取 Binder 驱动的消息而已,只注册一个 Binder 线程也是可以工作的,比如 service manager 就是这样的。实际上 Zygote 尽管没有采取 Binder 机制,它也不是单线程的,但它在 fork() 前主动停止了其他线程,fork() 后重新启动了。
主要是因为 Linux 是使用的虚拟内存寻址方式,它有如下特性:
Flutter 的 Widget 生命周期与 StatefulWidget 紧密相关:
通过 StreamBuilder 和 FutureBuilder 我们可以快速使用 Stream 和 Future 快速构建我们的异步控件。Flutter 中 runApp 启动入口其实是一个 WidgetsFlutterBinding,它主要是通过 BindingBase 的子类 GestureBinding、ServicesBinding、SchedulerBinding、PaintingBinding、SemanticsBinding、RendererBinding、WidgetsBinding 等,通过 mixins 的组合而成的。
Flutter 中的 Dart 的线程是以事件循环和消息队列的形式存在,包含两个任务队列,一个是 microtask 内部队列,一个是 event 外部队列,而 microtask 的优先级又高于 event。因为 microtask 的优先级又高于 event,同时会阻塞 event 队列,所以如果 microtask 太多就可能会对触摸、绘制等外部事件造成阻塞卡顿哦。
Flutter 中存在四大线程,分别为 UI Runner、GPU Runner、IO Runner,Platform Runner(原生主线程),同时在 Flutter 中可以通过 isolate 或者 compute 执行真正的跨线程异步操作。
Widget 会被 inflate(填充)到 Element,并由 Element 管理底层渲染树。Widget 并不会直接管理状态及渲染,而是通过 State 这个对象来管理状态。Flutter 创建 Element 的可见树,相对于 Widget 来说,是可变的,通常界面开发中,我们不用直接操作 Element,而是由框架层实现内部逻辑。就如一个 UI 视图树中,可能包含有多个 TextWidget(Widget 被使用多次),但是放在内部视图树的视角,这些 TextWidget 都是填充到一个个独立的 Element 中。Element 会持有 renderObject 和 widget 的实例。记住,Widget 只是一个配置,RenderObject 负责管理布局、绘制等操作。
在第一次创建 Widget 的时候,会对应创建一个 Element,然后将该元素插入树中。如果之后 Widget 发生了变化,则将其与旧的 Widget 进行比较,并且相应地更新 Element。重要的是,Element 不会被重建,只是更新而已。
继承(关键字 extends)、混入 mixins(关键字 with)、接口实现(关键字 implements)。这三者可以同时存在,前后顺序是 extends -> mixins -> implements。
Flutter 中的继承是单继承,子类重写超类的方法要用 @Override,子类调用超类的方法要用 super。在 Flutter 中,Mixins 是一种在多个类层次结构中复用类代码的方法。mixins 的对象是类,mixins 绝不是继承,也不是接口,而是一种全新的特性,可以 mixins 多个类,mixins 的使用需要满足一定条件。
本文整理了 Android 开发中大厂秋招的常见面试题,涵盖了 Java 基础、Android 核心机制、Framework 原理及 Flutter 框架知识。内容涉及抽象类与接口区别、线程状态管理、Handler 消息机制、Binder 跨进程通信、Zygote 启动流程等关键技术点。建议求职者结合官方文档与源码深入理解,并通过实际项目巩固知识点,提升面试通过率。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online