
2023年的小满秋招Android研发岗第一批笔试我全程跟下来了也把试卷里里外外复盘了一遍。这几天好几个学弟学妹跑来问题目偏原理还是偏工程有没有什么坑是不是要把Framework源码全背下来这里就把这次笔试的考点布局、答题思路、还有我踩过的坑一次性整理出来。无论你是准备Android校招还是打算社招跳槽甚至在公司里负责出题这份复盘都有参考价值。先说结论这场笔试不是典型的“八股文”考试它对底层原理、版本适配、构建工具链和跨领域技术视野都有涉及题量不小部分题目明显是拿“有没有真实做过项目”来筛人的。如果只刷题不实际写代码后面几道开放题基本拿不到分。1. 笔试整体结构与考察思路拆解1.1 考的不只是知识点而是“能干活的人”我拿到试卷的第一反应是出题人想得很清楚——他们要的不是“背得出AMS原理的选手”而是“能在AGP 8环境里正常编译、敢碰Binder和文件共享、能处理Android 14适配问题的人”。试卷大致沿着四条线铺开基础功底、系统机制、工程化能力、方向视野。基础功底指的是Java/Kotlin语法、集合、并发、数据结构系统机制是Android独有的一套东西比如Handler、Binder、AMS、View绘制工程化能力则集中在Gradle、AGP版本、R8混淆、依赖管理方向视野是目前行业里增长明显的领域包括车载、蓝牙、跨平台甚至鸿蒙生态。这样的结构说明了一个趋势Android研发岗笔试已经从“问你知不知道”变成了“问你有没有真正动手解决过问题”。举个例子如果候选人没在Android 7.0以上的设备上处理过FileProvider碰到content://开头的URI题目就很容易凭感觉瞎猜。1.2 题型分布与分值逻辑我根据回忆整理了一份试卷结构不同场次可能会有浮动但整体逻辑基本一致题型题量分值占比难度建议耗时单选题20题左右约30%中等25分钟多选题5题左右约10%中高10分钟简答题4题左右约20%中高30分钟手写代码题2题约20%高30分钟开放设计题2题约20%高25分钟选择题里Android知识占了大头穿插了少量Java并发和数据结构题目比如“HashMap在Java 8中链表转红黑树的阈值是多少”“Handler的dispatchMessage和sendMessage区别”这类细节题。多选题比较刁钻容易在“以下关于ContentProvider的说法正确的有”这种题干上挖坑。简答题是非常典型的Android系统机制题我印象里出现了“描述startActivity跨进程的完整流程”“Handler消息机制中IdleHandler什么时候被调用”等。代码题第一题是常规算法第二题直接让你实现一个支持数据监听的回调包装类考察泛型和线程切换。开放设计题更有意思给了几个场景比如“如果App冷启动从800ms优化到400ms你会从哪些方面下手”考察的是性能优化体系而非固定答案。2. 计算机基础与语言层题目复盘2.1 算法题手撕代码只是入场券这次笔试的算法题不算难至少没有出“字典树动态规划”这种地狱级组合。第一道是“LRU缓存”第二道是“验证二叉搜索树”。都是LeetCode中高频题难的是在笔试限时、不能编译器辅助的情况下把边界条件写对。以LRU缓存为例标准解法是HashMap加双向链表。我在写的时候先定义节点类再定义伪头部和伪尾部节点最后实现get和put。关键点是get时要把访问节点移动到头部put时如果容量满了要删除尾部节点。代码看似不长但很多人在“移动到头部”这步写错了指针指向。class LRUCache { class DLinkedNode { int key, value; DLinkedNode prev, next; DLinkedNode() {} DLinkedNode(int key, int value) { this.key key; this.value value; } } private MapInteger, DLinkedNode cache new HashMap(); private int capacity; private DLinkedNode head, tail; public LRUCache(int capacity) { this.capacity capacity; head new DLinkedNode(); tail new DLinkedNode(); head.next tail; tail.prev head; } public int get(int key) { DLinkedNode node cache.get(key); if (node null) return -1; moveToHead(node); return node.value; } public void put(int key, int value) { DLinkedNode node cache.get(key); if (node null) { DLinkedNode newNode new DLinkedNode(key, value); cache.put(key, newNode); addToHead(newNode); if (cache.size() capacity) { DLinkedNode removed removeTail(); cache.remove(removed.key); } } else { node.value value; moveToHead(node); } } }说实话这种题能不能拿满分主要看你平时写代码的习惯。如果练习时只关注“能跑通”而不关注“边界正确性”到了笔试现场就会在删除节点时漏掉prev指针的处理。我的建议是算法准备阶段每一道题都当作生产代码来写把判空、头尾节点、容量为0这些边界条件全部考虑进去。2.2 Java/Kotlin语言机制题原理不能只背结论语言层的选择题里有几道题特别容易错。第一道是关于synchronized和volatile的区别答案是“volatile保证可见性但无法保证原子性”但干扰项里出现了“volatile能替代synchronized保证线程安全”很多靠背题的同学就栽了。另外一道考Kotlin协程问“withContext和async/await的区别”这需要理解协程的调度器和结构化并发不是只看过几篇入门文章就能答对的。还有一道让我印象很深的内存泄漏题给出一段代码问以下情况哪些会造成“持有Activity引用导致泄漏”匿名内部类、静态变量持有View、Handler延迟消息、AsyncTask执行耗时任务。答案是四个选项都可能尤其是“静态变量持有View”这点容易被忽略——View本身持有Context引用被静态变量引用后Activity无法回收。这类题目的坑在于很多教程只告诉你“会有泄漏”或“不会泄漏”却不解释引用链。笔试真正想考察的是你能否画出完整引用关系图。我在准备阶段的做法是给自己讲明白每一步为什么匿名内部类会持有外部类引用为什么Handler的延迟消息会让MessageQueue持有Looper持有Handler引用再持有Activity。只有把引用链讲清楚碰到变形题才不会慌。2.3 数据结构与多线程的“跨界题”这次笔试出现了一道很典型的跨界题“设计一个线程安全的单例要求懒加载且性能尽可能高”。这题表面考单例实际考的是类加载机制、volatile、synchronized和指令重排。标准回答是“双重检查锁volatile”但如果面试官追问“为什么instance要用volatile修饰”很多人就答不上来了——因为new对象不是一个原子操作分配内存、初始化、引用赋值三步可能发生重排如果不加volatile其他线程可能看到半初始化对象。我答这道题时直接在代码里写了大段注释把“为什么需要volatile”“为什么第一个if判断可以减少锁竞争”都标注出来。笔试阅卷人不一定看代码细节但看到注释里的分析过程至少会认为你理解原理而非背代码。3. Android系统机制与Framework高频考点3.1 AMS、四大组件与进程模型基础但致命Android系统机制题是这份试卷的绝对重点。选择题里至少有五道直接考Framework简答题更是围绕AMS和进程模型展开。第一道简答题是“描述startActivity跨进程的完整流程”这道题如果准备过其实很好答App进程通过Binder调用ActivityManagerService的startActivity接口。AMS对Activity进行校验和任务栈调整解析Intent判断Activity所在进程是否存在。如果进程不存在AMS通过Socket或Binder请求Zygote进程fork出新进程。新进程的ActivityThread.main()启动创建Application然后通过Binder向AMS报告attach。AMS调用realStartActivityLocked最终通过ApplicationThread.scheduleLaunchActivity通知应用进程创建并启动目标Activity。ActivityThread收到消息后执行onCreate、onStart、onResume。丢分点集中在第3步和第6步。很多人知道要跨进程却说不清Zygote和AMS之间的关系还有人漏掉onStart和onResume的区分。答题时最好画一画调用链比如“AMS — Zygote — 新进程 — ActivityThread — ApplicationThread — Activity”分步描述就能把分值拿全。还有一道题问“系统为何要设计进程优先级低内存时优先杀哪个”这题本质是考察进程生命周期前台进程、可见进程、服务进程、后台进程、空进程。如果只说“后台进程会被杀”是不够的需要补充“进程优先级由Activity、Service、ContentProvider等组件状态动态决定”最好能说出Service在后台运行但被判定为后台进程的场景。3.2 Handler、Binder与线程模型Android的血液Handler消息机制几乎是每场Android笔试的必考题这次也不例外。选择题追问了“MessageQueue为什么会阻塞”“IdleHandler在什么时候执行”这类细节。IdleHandler这道题比较新很多人没准备到。它的定义是当消息队列当前没有需要立即执行的Message时才会回调的接口。要注意“没有立即执行的消息”不等于“队列为空”如果队首消息delay了10分钟IdleHandler一样会被执行。这个细节是区分“背过知识点”和“真正读过源码”的关键。Binder的简答题是“Binder相比其他IPC机制为什么更适合Android”答题要点是性能高一次拷贝安全性好内核为每个进程分配uid/pid实现面向对象调用使用代理模式。这里还可以顺手提到Intent、ContentProvider、Messenger底层都基于Binder向阅卷人展示你有一个完整知识网络。另外有一道关于“主线程为什么不能执行耗时操作”的多选题答案其实是“不只是因为ANR”还要从Looper只有一个、Handler消息串行执行、UI点击事件都需要主线程响应的角度回答。凡是只选了“因为会ANR”的大概率丢分。3.3 View绘制与事件分发UI题怎么答才不丢分View体系和触摸事件是UI岗考察重点在这次通用研发岗试卷里也占了不少分值。有一道选择题问“invalidate和requestLayout的区别”答案很简单invalidate会触发onDrawrequestLayout会触发onMeasure和onLayout。但这题真正的坑在于“在子线程调用invalidate会怎样”——很多老版本资料会说“必须在主线程”实际上从Android 4.1开始ViewRootImpl只在主线程校验invalidate本身是线程安全的子线程调用时内部会通过ViewRootImpl检查线程。这类细节题如果没有实际跑过很难答对。关于触摸事件简答题考了“事件分发三个方法dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent它们之间的调用顺序是什么”。标准流程是Activity.dispatchTouchEvent - ViewGroup.dispatchTouchEvent - ViewGroup.onInterceptTouchEvent - 子View.dispatchTouchEvent - 子View.onTouchEvent - 父View.onTouchEvent。关键点在onInterceptTouchEvent一旦返回true后续事件将不再询问子View而是直接走父容器的onTouchEvent。另外热词里出现了“android中协调布局banner”这道题很有意思出题人大概率让你用CoordinatorLayout实现一个“顶部Banner图片跟随手指伸缩/上滑折叠”的效果考察的是自定义Behavior。答案核心是AppBarLayout.ScrollingViewBehavior或自定义Behavior的onDependentViewChanged回调在Banner滚动变化时动态设置View的scale或高度。如果平时没用过CoordinatorLayout单靠背Behavior原理是写不出完整方案的。3.4 ContentProvider与文件访问从URI暴露出的出题意图我在试卷上看到一道非常接地气的选择题“以下哪种方式可以安全地在两个App之间分享一个本地图片文件”选项里有file://绝对路径、ContentProvider、公共目录、全局可读写SharedPreferences。这道题只要是Android 7.0之后做过开发的人都知道file://会抛FileUriExposedException应该用FileProvider生成content:// URI。这背后就是热词里反复出现的content://com.baidu.searchbox.fileprovider这类字符串的含义。FileProvider的配置不复杂在Manifest里声明Provider在xml里配置paths核心是getUriForFile方法生成URI。但笔试里常考的是原理为什么不能直接用file://因为App之间没有共享文件系统权限直接传递路径会让接收方没有权限读取而FileProvider把文件访问权限通过grantUriPermission临时授权给目标应用本质上是把“路径访问”转换为“权限受控的资源访问”。这类题目其实是在提醒大家阅读日常崩溃日志时不能只盯着业务代码要能看透ContentProvider、Binder这些系统组件是怎么协作的。平时遇到FileUriExposedException如果只“百度搜到一个加FileProvider的解决方案”就完事笔试遇到变形题还是会懵。4. 新版本适配与构建工具链能力考察4.1 Android 14、分区存储与OTA系统升级题怎么答如果说上面几道题还算常规那这份试卷对Android 14和系统OTA的考察明显是想把应用开发者和系统开发者的要求合并成一个人。热词里大量出现的“android 14 root”“android ota”就来自这些题目引发的搜索。有一道简答题是“App适配Android 14API 34需要关注哪些行为变化”我从记忆里拼出几个重点前台服务类型必须声明、动态广播接收器需要指定导出状态、predictive back动画默认关闭但需要适配、targetSdkVersion达到34后无法关闭Big Picture通知等。实际笔试时我也是按“权限收紧、组件安全、用户体验变化”三个维度来答的这样不管出题人问哪一点都能有一套逻辑框架兜底。另外一道选择问“OTA升级包是如何被系统应用的”这题对大多数应用开发同学来说偏冷门。答案大概分四步检测到升级包后写入misc分区并广播升级意图重启进入Recovery模式Bootloader引导加载升级脚本升级完成后重启进入新系统。答题时不需要写多深但至少要知道OTA不是直接往当前运行的系统里灌镜像而是通过独立的Recovery分区完成的。4.2 AGP、Gradle与Android Studio版本环境题是送分也是陷阱笔试选择题里有一道让我愣了几秒“Android Studio Hedgehog 2023.1.1 Patch 2 默认支持哪一档AGP 8.x”如果没被热词里的问题折磨过这道题确实容易懵。事实上AGP和Gradle、Android Studio之间存在严格版本映射关系AGP 8.0要求Gradle 8.0AGP 8.1要求Gradle 8.0AGP 8.2要求Gradle 8.2。Android Studio Hedgehog 2023.1.1可以支持AGP 3.2到8.2左右的版本范围再新的需要升级IDE。这类题目考察的是真正的“环境配置能力”。很多项目报错“Could not load compiled classes for settings file”根本原因就是Gradle版本和AGP版本不匹配。笔试里虽然不会让你真跑一次构建但出题人通过这道题来判断你日常是不是“打开Android Studio点了Run就跑”的人。我的建议是把AGP、Gradle、JDK三者的版本关系记成一张表放在笔记里AGP版本最低Gradle版本JDK要求7.47.5JDK 118.08.0JDK 178.18.0JDK 178.28.2JDK 17注意JDK版本从AGP 8开始强制要求17如果项目里还在用JDK 11升级AGP后会出现一堆编译报错。笔试里不一定会直接问“JDK版本”但会通过“AGP 8.0项目使用Gradle 7.x会怎样”这种变形题来考。4.3 R8、混淆与包体积优化性能优化题怎么答有同学看到热词里的“android r8”以为试卷考了很多混淆题目其实真正考到的是一个选择题“R8相比ProGuard有哪些区别”正确答案包含三条R8同时承担压缩、优化和混淆R8会在优化阶段移除未使用的代码和资源R8对Kotlin的元数据支持更好。有一个明显的陷阱是“R8只能和AGP 7.0以上版本配合使用”实际上R8早在AGP 3.4就引入了只是后来成为默认。另一道开放题是“如何降低APK体积”我分析了几个方向使用App Bundle按需分发、资源混淆和资源瘦身、移除无用依赖、开启R8压缩、考虑使用动态特性模块、图片WebP化和矢量图化。这里有个答题技巧最好能写出具体收益比如“R8开启后一个空项目能从2MB降到1.2MB左右”没有数据支撑的方案在阅卷人看来就是泛泛而谈。5. 技术扩展与行业方向笔试里的“超纲”题5.1 车载、蓝牙、硬件调试岗位期望比想象中广从热词里能看到大量方向性词汇android车载、android蓝牙、i2c-tools在android上使用、android openocd。这说明这次笔试的岗位画像不是“纯应用层开发”而是更贴近系统定制、智能座舱或者硬件交互方向。比如i2c-tools在Android上的使用本质是在Android设备上通过I2C总线读写传感器芯片。如果笔试里出现“如何调试一个不工作的I2C外设”常见的回答是确认设备节点在/dev下是否存在使用i2cdetect扫描总线地址确认驱动是否加载到内核用i2cget/i2cset读取寄存器值。这一套流程属于典型嵌入式开发经验但很多只写App的同学可能连“/sys/class/i2c-dev”都没听过。车载Android的考察点则更多集中在车机系统定制、多屏交互、永不休眠等特性上。笔试不会深挖但开放题里给一个“车机竖屏和手机横屏同时显示不同内容”的场景其实就是考察多窗口和Configuration变化的知识。5.2 跨平台、多媒体与鸿蒙生态研发视野题热词里还有qt5配置android环境、android smartplayer集成、harmonyos next 5.0、a支持ios 11.0及以上/Android 4.0及以上等。这些词综合起来看出题人是想考“你是否有跨平台和多端交付意识”。有一道选择题我印象很深“某SDK宣称支持iOS 11.0及以上、Android 4.0及以上发布时需要关注的兼容性问题是什么”选项包括API级别差导致的代码分支、浏览器能力兼容、最低版本设备性能约束等。正确答案基本覆盖了“SDK要兼容的系统碎片化问题”。如果是做过SDK打包的开发者对这些一定很熟悉。HarmonyOS NEXT则是在考“应用层开发者是否关注生态变化”。这道题不要求你熟练使用ArkTS只要求能说出“NEXT版本不再兼容Android APK需要单独开发鸿蒙版本”这一基本事实。热词里有“harmonyos next 5.0及以上”也说明当前生态适配的话题热度很高。笔试现场遇到这种题目保持客观即可不需要站队或吹捧任何技术。5.3 MVVM与架构模式代码题背后的工程化要求架构题的考察藏在代码题里。第二道手写题要求实现一个“可感知生命周期的数据绑定回调”本质上就是让你动手写一个简化的LiveData。关键词“android studio mvvm代码示例”说明很多同学在准备时专门搜索了MVVM模板。笔试中这类题通常不要求完全实现ViewModel和LiveData的全套机制但要求能体现几个关键思想数据驱动UI、生命周期感知、避免内存泄漏。我在答题时写了一个类内部持有观察者列表在setValue时遍历回调同时用LifecycleOwner判断当前生命周期状态避免在后台时执行UI更新。代码不复杂但把这些注释写在关键行旁边阅卷人一眼就能看出你理解MVVM的本质。6. 机试答题策略与常见失误6.1 时间分配与答题顺序先做代码题我个人的建议是根据自己的情况决定但有一个原则不要在一道选择题上耗超过2分钟。笔试链接里有题目计时单题耗时过久会压缩后面大题的书写时间。我当时的策略是先花5分钟浏览全卷把简答题和代码题在脑内排个优先级——会写的先写、能拿分的先拿分然后再返回补选择题。6.2 三种“会做但没分”的典型错误只给思路不写代码开放设计题要求“给出实现方案”你只写“用MVP实现就好”没有任何细节等于没答。代码直接写中文注释代替逻辑实现有人会把“在这里判断容量如果超过则删除最久未使用的节点”当作答案这不会得分。手写代码不考虑线程安全LRU缓存如果要求“线程安全”你直接写HashMap就是错。6.3 复盘笔记考完不是结束而是开始笔试结束后我习惯在一个文档里把每道题对应到知识点标记哪些是“已掌握”哪些是“模糊”哪些是“完全不会”。这次让我补课的主要有三块FileProvider的跨应用授权细节、IdleHandler的触发条件、AGP与Gradle的版本映射表。每一块都值得花一晚上查源码或看官方文档而不是只搜一篇博客看结论。老实说这场笔试的难度不算顶尖但覆盖面确实很宽。如果平时只做应用层业务开发很容易在版本适配和构建工具链上露怯如果只刷系统源码但没写过实际项目又会在性能优化和跨端意识上丢分。准备思路还是那句话把自己当作一个“需要交付完整Android产品的工程师”去补全能力地图而不是针对某一道题去突击。这样无论是遇到content://、android studio版本还是开源播放器集成心里才都有底。