尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

哔哩哔哩Android校招笔试题详解:核心考点与底层原理

哔哩哔哩Android校招笔试题详解:核心考点与底层原理 前几天整理网盘翻到自己当年存的一份笔试回忆版文档正好是哔哩哔哩2020校园招聘 Android 方向笔试卷一的整理稿。那会儿为了秋招刷了不知道多少套题现在回头看这套卷子其实非常能代表视频类大厂Android校招的出题风格。它没有太多偏题怪题但每道题都在考察你是不是真的理解Android底层机制而不仅仅是会写几个Activity。这篇文章我就结合这份卷子把考点、答题思路、以及我踩过的坑摊开聊一聊给正在准备Android校招的同学做个参考。不管是科班还是培训班出身只要你打算投Android开发岗这套卷子覆盖的知识点基本是你绕不过去的。适合正在刷校招真题的人、准备跳槽想自测基础的人也适合那些刚开始学Android、想搞明白到底要学多深的人。我会按题型和考察模块一条条拆尽量把每个考点背后的原理讲透而不是单纯给答案。1. 先还原一下这张卷子的真面目题量、题型与考察重点1.1 我印象里的试卷结构这份卷子当时是线上笔试时限大概90分钟到120分钟整体题量不小。题型分布大概是这样的单选题、多选题、判断题、2到3道编程题、最后还有一道开放设计题。我记得单选题大概有15到20道多选和判断各占一部分编程题的时间压力比较大开放题则完全看你怎么组织思路。从考察范围来说这份卷子做下来最大的感受是它把计算机基础、Java语言、Android框架、性能优化四块内容全塞进了一套题里。计算机基础部分考了操作系统的进程与线程、死锁条件、网络分层Java部分考了集合源码思想、并发、JVM内存区域Android部分则是重头戏Activity启动模式、Handler机制、事件分发、自定义View、内存泄漏这些高频考点一个都没落下。也就是说如果你只准备了Android四大组件的使用方法而没有系统复习Java并发和操作系统做起来会非常吃力。1.2 单选题覆盖很广但深度有限单选题整体难度适中但有个特点喜欢在看似基础的题目里埋坑。比如它会问以下哪个不属于Activity的启动模式选项里有standard、singleTop、singleTask、singleInstance加上一个singleFrom如果你只是背了四种模式的名字看到singleFrom这个选项可能犹豫一下但仔细想想就会发现这是编出来的干扰项。这类题考的不是你能不能写出代码而是概念是否精确。还有一类单选题考的是源码层面的理解。比如问startActivity最终是通过什么方式启动Activity的选项里有ActivityManagerService、ActivityManager、ActivityThread、Instrumentation这样的词。如果你没看过启动流程就知道选AMS但如果你稍微深入一点会发现真正调用是Instrumentation.execStartActivity然后通过AMS完成进程间通信。这种题表面上在考AMS实际上是在考你对系统服务调用链的熟悉程度答案不是一个名字而是一条链。1.3 多选题与判断题比单选更能筛人多选的厉害之处在于漏选、错选都不得分所以它比单选更考验知识的完整度。比如有一类题考哪些情况会导致内存泄漏选项包括Handler持有Activity、静态Context引用、非静态内部类、BroadcastReceiver未注销、文件流未关闭。大部分人都能选对前四个但如果漏掉文件流未关闭这种非典型泄漏点整题就丢了。这类题要求你在平时写代码时就有意识积累各种泄漏场景而不是考前突击。判断题相对友好一些但陷阱也不少。它常见的手法是把一句话说得非常绝对比如View.post方法一定会执行在UI线程这句话看起来没问题但如果View还没有附加到窗口post的Runnable会被放到一个待执行队列等attach后才会执行而且执行的线程也不一定是UI线程。这么一来判断题考的其实是边界情况不能只看表面字义。2. Java并发与内存模型笔试中隐藏的送命题2.1 线程安全问题不只是一道synchronized和ReentrantLock区别这套卷子里Java并发的比重比我想象中高。它不会直接让你写一个多线程程序而是用选择题、判断题的方式反复考你对线程安全、锁机制、线程通信的理解。比如有一道题给了一段代码两个线程同时对一个int变量做i操作问你最后结果可能是多少。如果对并发没有概念的人可能会觉得结果是确定的但i不是原子操作它对应读、加、写三步两个线程交错执行时结果可能比预期的要小。更深一层卷子里还出现了关于synchronized和ReentrantLock的选择题问两者的区别。这类题目如果只答一个是关键字一个是类是不够的还要知道可重入、可中断、公平锁、条件变量这些细节。我的建议是把锁相关的知识点整理成一张对照表包括用法、底层实现、性能差异、适用场景。另外volatile和synchronized的区别也是高频考点这块特别容易混淆要记清楚volatile只能保证可见性和有序性不能保证原子性。2.2 内存泄漏与GC从JVM到Android的延伸Java内存这块B站的题喜欢从JVM延伸到Android。比如它会问强引用、软引用、弱引用、虚引用的区别然后进一步问在Android中软引用和弱引用分别适合什么场景。如果你只背了定义不知道Android里的具体应用这题就很难拿全分。实际上Android中软引用适合做图片缓存这类对内存敏感的场景弱引用适合Handler持有Activity这种容易泄漏的场景而虚引用通常跟清理直接内存相关。GC相关题目也很典型比如问以下哪项不是可达性分析中GC Roots的候选对象。选项可能包括虚拟机栈中引用的对象、方法区中静态变量引用的对象、常量池中引用的对象、所有线程对象。答案是所有线程对象因为线程本身不是GC Roots只有被线程栈帧引用的对象才是。这类题跟Android的LeakCanary原理直接相关LeakCanary本质上就是用弱引用加ReferenceQueue做可达性分析笔试里考这个实际是在考察你对线上内存问题定位的理解程度。2.3 一个容易写错的并发编程题示例编程题里Java并发也可能出现。我印象中有一道题是让实现一个生产者消费者模型要求使用wait/notify或者Lock/Condition实现规格是缓冲区大小固定。这种题看起来简单但很多人在写的时候会出现两个问题第一wait方法没有放在while循环里而是用if判断一旦存在多个消费者同时被唤醒就可能出现数据越界或重复消费第二notify和notifyAll的选择搞不清楚notify只唤醒一个线程如果唤醒的是同类线程就可能出现所有线程都在等待的假死状态。正确写法是条件判断用while唤醒时用notifyAll或者用Condition的signal和signalAll来精确控制。如果你用ReentrantLock实现还可以用两个Condition分别表示队列满和队列空这样唤醒时天然只会唤醒对应类型的等待线程代码逻辑更清晰。这道题如果在笔试中被要求写上注释建议把线程状态切换和条件等待的原因写清楚阅卷人能从这些细节里分辨出你是背的模板还是真的懂并发。3. Android四大组件与Handler机制校招笔试的必考大轴3.1 Activity启动模式背了四种模式还不够Activity启动模式几乎是每套Android笔试试卷的保留节目B站这份也不例外。但它的考察方式不是让你默写四种启动模式而是考不同模式组合下的具体行为。比如standard模式启动同一个Activity会创建多个实例singleTop如果栈顶已经有该实例就不会新建singleTask会清除栈顶其他ActivitysingleInstance则单独占一个任务栈。难点在于把这些模式放到具体场景里。笔试里有一道题问的是一个App从通知栏点击通知跳转到某个Activity再点击返回键应该回到哪个页面。这其实就是在考taskAffinity和singleTask之间的配合以及Intent的FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP对栈的影响。只背名字的人遇到这道题会直接懵掉因为它考察的是任务栈的结构变化。复习建议是打开手机开发者选项里的显示布局边界或者用adb shell dumpsys activity activities命令亲手试几种启动模式观察task中Activity的排列变化比死记硬背高效得多。3.2 Service与进程保活这类题背后的意图Service这道题我觉得挺有B站风格因为它和音视频播放、后台下载这些业务强相关。卷子里问的是启动Service的两种方式和它们的区别即startService和bindService看到题目的时候可能觉得简单但后面接着问如果Activity被销毁Service应该怎么处理。如果只知道startService会一直运行、bindService跟Activity生命周期绑定这道题答到这一步也就够了但如果再深入问如何在Service中执行耗时任务就需要区分IntentService、普通线程和JobService的适用场景。进程保活这种题当时也出现过问的是以下哪种方式可以提升进程优先级减少被系统回收的概率。选项里有前台Service、双进程守护、播放无声音乐、WorkManager。如果你经常看各种国内App的保活教程可能会纠结双进程守护但说实话在Android 8.0之后后台限制越来越严双进程守护已经很难奏效了正确的主流方案是前台Service加WorkManager。这道题表面在考后台任务实际上是在看你的技术方案能不能跟上系统版本演进这是一个很容易在笔试里暴露短板的地方。3.3 Handler机制从Looper到消息屏障把为什么讲清楚Handler机制在B站这份卷子里出现得有点多单选里考了多选里也考了编程题旁边还有一道简答题。问法大概是为什么主线程的Looper不用手动调用loop方法也能不断处理消息。很多人知道ActivityThread里有Looper.prepareMainLooper和Looper.loop但说不清楚为什么主线程崩溃后系统会重启应用以及Looper.loop是一个死循环它为什么不会导致主线程卡死。这里的关键在于理解epoll机制。主线程的Looper.loop会进入一个无限循环不断从MessageQueue里取消息如果没有消息就会调用nativePollOnce进入休眠释放CPU一旦有新消息系统通过epoll机制唤醒主线程。唤醒期间CPU是空闲的所以不会造成性能浪费。而ANR的本质不是主线程有死循环而是某个耗时操作阻塞了Looper取消息导致后续的输入事件和绘制消息无法及时处理。笔试里如果把阻塞和死循环混为一谈这道题就危险了。还有一道关于消息屏障的判读题选项里说同步屏障会拦截所有消息。这句话是错的。同步屏障只拦截同步消息不拦截异步消息。在View绘制流程里系统会插入一个同步屏障来确保绘制消息优先执行等绘制结束后再移除屏障。这个点如果不看源码很难答对但它确实是Handler机制里最能区分水平的问题之一。4. View体系、动画与事件分发拉开差距的地方4.1 事件分发别只背三个方法事件分发是Android笔试里公认的难点B站这份卷子自然也没放过。选择题里给了一个场景一个LinearLayout里嵌套一个TextView点击TextView时三个方法dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent的调用顺序是什么。如果背过结论知道顺序是Activity ViewGroup View然后反向回溯但这只是第一层。题目真正想考的是事件被消费后哪个方法会返回true以及OnTouchListener和onTouchEvent的优先级关系。很多人在这个点上栽跟头如果View设置了OnTouchListener且onTouch返回true那么onTouchEvent就不会被调用。这直接关系到你在开发中能不能解释为什么我明明在onTouchEvent里写了逻辑却不执行。我的建议是自己写一个Demo重写三个方法并把调用日志打印出来用真实的点击事件验证一遍。别看这个原理很基础笔试里多选一旦涉及哪些返回值会导致事件被消费这种组合题没有实际验证过的人只能靠猜。4.2 自定义View与绘制流程题目不会直接考画圆自定义View在笔试里一般不要求你手写完整控件而是会问绘制流程中的几个关键环节。比如measure过程里MeasureSpec的三种模式UNSPECIFIED、EXACTLY、AT_MOST分别对应什么场景。如果你只是背了定义碰到ScrollView中嵌套一个高度为wrap_content的RecyclerView这种现实的测量问题还是不知道怎么回答。正确理解是父容器会给子View一个带着模式和大小的MeasureSpec子View要根据这个MeasureSpec决定自己的尺寸。还有一道题问的是invalidate和requestLayout的区别。很多人在刷题阶段容易把这两个方法混淆。invalidate会触发onDraw重新绘制但不会重新测量requestLayout会触发onMeasure和onLayout如果不涉及尺寸变化用invalidate就够了。笔试出这一题其实是在考察你是否理解布局和绘制的分离。实际开发中如果频繁调用requestLayout很容易造成UI抖动和性能问题这是一个很隐蔽的坑。4.3 性能优化与内存优化卷子上一定会出现的综合题性能优化这部分在B站这份卷子里不是单独问什么是卡顿而是给了一段代码让你找问题。我记得有一道题展示了一个列表滑动卡顿的代码片段里面有在Adapter的getView里做磁盘读取和复杂计算还用了多个嵌套的LinearLayout。题目问的可能导致卡顿的原因有哪些。选项包括在主线程执行耗时操作、布局层级过深、ViewHolder未复用、图片未压缩。这种题本质上考的是性能优化的综合能力不是单一知识点。布局层级过深会导致measure和layout阶段耗时增加ViewHolder未复用会在滑动时频繁创建View磁盘IO会阻塞主线程。图片问题在视频类App场景下尤其突出因为列表里如果加载大图内存和绘制压力都很大。备考时可以多看看官方文档里关于性能优化和布局优化的建议以及常见的Profile工具使用方式。笔试可能不会考具体怎么用systrace但会考你能否识别代码中的性能隐患这算是一个加分能力的初级门槛。内存优化里面还有一个很常考的细节Bitmap的内存计算。题目会给一个100x100的ARGB_8888格式图片问它占多少内存。100x100x4字节等于40000字节约39KB。如果图片放在drawable-xhdpi目录而设备是xxhdpi还涉及资源目录密度缩放内存占用会更大。这种题看似在考计算实际上是在考察你是否理解Android资源系统对图片的缩放机制。很多人只背了ARGB_8888是4字节没有考虑资源目录和屏幕密度的关系遇到这种带上下文的题目就会失分。5. 编程题和开放题手写代码时考官想看到什么5.1 手写单例与线程安全最常出现的代码题编程题的第一道通常是基础题手写常见的单例模式或者工具类。B站这套卷子里我印象中有一道是手写双重检查锁定的单例并要求说明为什么用volatile。很多人能写出double-check的模板但问到volatile就卡壳了。原因在于创建对象不是原子操作指令重排可能导致另一个线程拿到一个未初始化完成的对象。volatile在这里的作用是阻止重排序保证instance在被赋值前构造已经完成。这道题的加分写法是使用静态内部类方式实现单例它借助JVM的类加载机制天然保证了线程安全代码也更简洁。如果笔试时间允许最好把两种实现都写出来并注明各自的优缺点。阅卷人能从这种细节看出你是有工程经验还是只背了八股。题目本身不难但手写代码的规范程度、注释意识、以及对并发安全的敏感度比最终代码能不能跑更重要。5.2 开放题如果让你设计XXX你该怎么组织语言开放题是我当时做这份卷子最没底的部分因为它没有标准答案。题目大意是让设计一个短视频列表的缓存方案要求考虑内存、磁盘、网络三个层面的策略。这种题对项目经验少的人来说很容易写空堆一堆使用三级缓存使用内存缓存和磁盘缓存这种话没有落地细节。我当时的做法是先定义清楚使用场景再说技术选型最后说异常处理。比如内存层用LruCache按设备可用内存的八分之一设置大小磁盘层用DiskLruCache或者自己封装文件缓存key用视频Id和清晰度组合网络层用OkHttp的缓存机制同时配合预加载策略滑动到倒数第二个item就提前拉取下一批数据。每说一个方案一定要跟上为什么这么做和有什么代价。比如LruCache虽然快但视频文件太大不能直接全放内存所以要先压缩封面图、把视频文件放磁盘。开放题考的不是你用过哪个框架而是你有没有形成一套技术决策的思考方式。5.3 答题技巧从卷面到代码的规范细节编程题还有一个容易丢分的地方是代码规范。有些人思路是对的主流程也写出来了但变量命名用了a、b、c方法名用了doSomethingtry-catch里直接吞掉异常。笔试阅卷通常没有单测能跑所以代码的可读性和严谨性反而成了评分的重要依据。我建议平时练习时就养成这样的习惯方法名用动词开头表达意图变量名能看出业务含义边界条件要在注释里说明。另外一个细节是如果题目要求分析时间复杂度一定要写清楚。哪怕代码只写了个大概时间复杂度的推导过程也能体现算法的基本功。比如要求实现一个LRU缓存你用LinkedHashMap实现需要说明get和put都是O(1)复杂度还要提到LinkedHashMap的accessOrder参数决定了LRU的顺序这才是真正的加分点比工整的模板代码更让阅卷人印象深刻。6. 考完复盘从这份卷子看B站校招的选人逻辑6.1 哪些题是用来筛选的哪些题是用来定级的做完这套卷子我最大的感觉是它不像某些公司那样故意出偏题来炫技而是很务实地在看候选人的基础扎实程度。单选题和多选题覆盖的知识点基本是一个Android开发平时写业务必须理解的东西。如果你能被这些基础题筛掉说明你确实还没有做好准备这跟刷了多少套题关系不大跟平时写代码时有没有多问几个为什么关系很大。开放题和部分源码级别的选择题则是用来定级的。同样一份卷子有人Handler机制只能答出用来发消息有人能画出MessageQueue、Looper、Handler之间的关系图并解释IdleHandler和同步屏障的用途那结果肯定是两个级别。所以不用过分纠结自己没复习到某个冷门知识点核心是把主流高频考点学深学透在开放题里展现出你的系统思考能力这样即便拿不到满分也有机会进入面试环节。6.2 刷题之外的准备项目经验如何配合笔试笔试不是全部但它会倒逼你整理知识体系。我当时有一个很笨但很有效的方法每刷一份卷子就把错题和不确定的题整理进表格分为概念不熟源码没看场景没经历过三类然后每类对应补知识点。比如场景没经历过里的内存泄漏场景我会专门拿LeakCanary去检测自己的项目亲眼看到泄漏提示再修掉印象就特别深。项目经验在笔试里看似用不上但其实很有用。遇到开放设计题处理过真实项目的同学往往会提到边界条件、异常状态、用户体验这些细节。比如视频缓存设计真实项目里要考虑弱网重试、磁盘空间不足、视频文件被清理的时机这种颗粒度的思考是刷题刷不出来的。如果你还有时间不妨在准备笔试的过程中同时维护一个自己的练手项目把学到的知识点放进项目里验证笔试和项目能力会一起长进。6.3 给后来人的备战建议现在回过头看我认为备战这一类大厂Android校招笔试最忌讳的是只刷题不总结最有效的做法是建立知识点之间的连接。单纯背Activity启动模式不如把启动模式、任务栈、Intent Flag、进程和任务的关系放在一起看形成一张网。单纯背Handler的原理不如把Looper、MessageQueue、epoll、ANR、IdleHandler、同步屏障全部串起来你会发现它们其实是同一个故事的不同章节。练习编程题时建议准备一个本子把每道题的错误原因写下来尤其是那些我以为我会但实际写错的题。这类题往往是你知识体系里的薄弱点也是笔试中最容易失分的地方。我当时就吃了不少这个亏比如手写快速排序时在partition边界条件上翻车以及并发代码里漏掉volatile这些问题如果不在平时暴露考场上很容易再犯。另外有条件的话找一个同样准备Android校招的同学一起组队刷题互相讲题、互相挖坑理解和记忆都会扎实很多。最后笔试只是校招流程中的一环不是终点。B站这份卷子做的不好也别灰心把它当成一次体检查出来的问题才是你接下来要重点补的方向。我自己后来面试时很多被追问的细节恰恰是当时笔试复盘时补上的。多练几套、多沉淀几轮你会发现那些原本模棱两可的知识点慢慢都变得确定起来。
返回列表