尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

2017年Android校招笔试B卷核心考点解析与备考实战经验

2017年Android校招笔试B卷核心考点解析与备考实战经验 欢聚时代YY的校招笔试在当年算是比较有代表性的题目难度中等偏上既考察Java和Android基础又涉及不少实战经验不像有些公司纯考背诵题。这份2017年Android工程师B卷我印象里整体风格很“业务落地”也就是说它不问你“Activity启动流程背一遍”而是喜欢给你一个具体场景让你分析该怎么处理。这篇文章我就结合这套题把里面的核心考点、我当时踩过的坑、以及现在回头看依然值得注意的知识点一起拆开聊聊。1. 整体笔试题型与备考思路先说卷面结构。2017年前后的校招笔试大厂普遍还是线下纸质试卷或者在线答题系统题型基本是三板斧选择题、填空题、简答题/编程题。B卷整体题量不算特别大但覆盖面很广。如果你手头有当年的题你会发现它大致分成四个模块Java基础知识、Android核心机制、实战场景设计、算法与逻辑思维。这四个模块不是割裂的很多题是交叉的比如用Java的泛型考你对集合的理解用Android的消息机制考你对线程通信的认识。我的建议是不要死记硬背概念要把每个知识点当成一个“工具”想清楚它解决什么问题、代价是什么、有没有替代方案。这份B卷的命题人显然也是这个思路因为很多题如果只是背概念根本答不到点子上。举个典型的例子关于Handler机制的题它可能会问“子线程能不能直接new Handler为什么”。你要是只回答“不能因为子线程默认没有Looper”那只能拿一半分。它更希望你能说出来主线程的Looper是在什么时候创建的、子线程里调用Looper.prepare()和Looper.loop()之后消息循环是怎么跑起来的、Handler.post()和View.post()有什么区别这样的细节。当年我备考的时候习惯把每个知识点拆成“是什么、为什么、怎么用、坑在哪”四个维度去梳理。笔试不比面试没有追问的机会所以你必须在有限的篇幅里把逻辑闭环写清楚。尤其是简答题尽量用“分点说明”的方式比如“第一在Application中初始化全局配置因为进程启动最早第二在ContentProvider中进行延迟初始化因为这是Android提供的生命周期回调第三使用依赖注入框架来管理单例作用域”。这样阅卷人一眼就能看出你是有工程经验还是纯背书。另外B卷和A卷通常只是题目顺序或个别题目不同核心考点不会差太多。如果你能拿到A卷做对比你会发现高频考点永远是那几个四大组件、Handler、Binder、内存优化、自定义View、网络框架、数据结构。所以备考的策略应该是“广覆盖、重深度”不要押题但要把高频考点的每一个细节都吃透。2. 高频基础考点拆解Java与Android核心这一部分我挑几个我认为在这份B卷里出现概率极高、而且即使放到今天依然是面试必问的知识点逐个拆开讲。2.1 Java内存区域与对象回收这道题几乎是所有Android笔试的标配B卷自然也不例外。它通常不会直接问“JVM内存分为哪几块”而是会给你一段代码让你分析对象在何时被回收或者问你“内存泄漏”产生的根本原因。要答好这类题首先得把Java内存模型刻在脑子里程序计数器、虚拟机栈、本地方法栈、堆、方法区在JDK8之后被元空间替代。对Android来说特别需要关注的是堆和栈。栈主要存局部变量和引用变量方法调用结束自动出栈堆存对象实例需要GC回收。但Android的Dalvik/ART虚拟机GC机制和标准JVM有点区别早期的Dalvik用的是CMS-like的并发标记清除ART在Android 8.0之后用的是并发紧凑收集器这导致一个问题内存碎片化。所以你写代码时如果频繁创建大对象很容易触发GC导致掉帧。关于对象回收判定最常见的是可达性分析算法。从GC Roots出发如果能到达的对象就是存活的不能到达的就是可回收的。GC Roots主要包括虚拟机栈中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI引用的对象。在Android里常见的内存泄漏场景就是长生命周期的对象持有短生命周期对象的引用典型的比如Activity被静态变量持有、Handler匿名内部类持有外部Activity、单例模式中传入了Activity的Context。这些场景在笔试里答出来不难但如果你能把“为什么会泄漏”讲清楚——是因为GC Roots链路上无法断开——那就显得更专业。另外B卷很可能考到引用类型。强引用、软引用、弱引用、虚引用的区别和适用场景要能倒背如流。特别是WeakReference在Handler内存泄漏解决方案中的应用还有软引用做缓存已经被官方不推荐了因为SoftReference在Android上从Android 9开始就更容易被系统提前回收这些细节都能体现你对Android特性的深入理解。2.2 Android四大组件的工作过程四大组件是Android的骨架B卷不可能绕过。但2017年的命题趋势已经不再是让你背“Activity生命周期”表而是倾向于考“启动模式”“进程与组件的关联”“隐式Intent匹配规则”这类有逻辑深度的内容。Activity的启动模式standard、singleTop、singleTask、singleInstance是必考项但B卷很可能升级考法给你两个ActivityA启动B然后按Home键再点击桌面图标问你会发生什么或者问你singleTask模式下Activity的回调顺序onNewIntent先于onRestart还是后于。这些细节如果平时没在真机上验证过很容易答错。我记得我当时就栽在onNewIntent和onRestart的顺序上后来专门写了个Demo测了一下singleTask模式复用栈内实例时顺序是onPause - onNewIntent - onResume如果是冷启动到热复用的场景还涉及onStop和onRestart具体要看栈内位置。所以这类题平时一定要动手实验。Service和BroadcastReceiver的考点通常集中在Service的两种启动方式的区别、startService和bindService混合使用的生命周期、进程被杀死之后Service的恢复机制START_STICKY、前台Service与通知栏的关联。2017年正值Andorid 8.0O前后后台执行限制和通知渠道是新东西笔试如果考到“如何让Service在应用退到后台后仍然存活”你得能说出WorkManager的前身也就是JobScheduler和AlarmManager的取舍以及为什么不能无条件靠Service保活。当年保活黑科技满天飞但命题人更希望看到你理解系统限制的本质而不是只知道“双进程守护”那种野路子。ContentProvider在笔试里一般不会单独出大题但会作为场景题的一部分。比如B卷如果考到“如何实现应用间数据共享”你光答ContentProvider就不够还得说出ContentResolver的调用方式、UriMatcher的用法、以及多线程并发访问时的线程安全处理insert/update需要加锁。另外2017年Google在Android 7.0上推出了FileProvider用于替代file://的Uri暴露这在笔试里是个很好的加分点。你能主动提到“在Andorid 7.0之后使用FileProvider可以避免FileUriExposedException”阅卷人对你的好感度会上升不少。2.3 Handler消息机制与线程通信Handler是Android的灵魂也是B卷的“钉子户”。不管题目怎么变核心永远围绕“一个线程如何将任务切换到另一个线程执行”这个本质问题展开。要答好Handler你需要完整掌握四件套Looper、MessageQueue、Handler、Message。这几个类的关系一句话就能概括Handler通过sendMessage把消息塞进MessageQueueLooper死循环从MessageQueue里取消息再分发给Handler的handleMessage处理。但光有这句话还不够你要能画得出消息在哪个线程入队、在哪个线程出队以及ThreadLocal在这个机制里扮演的角色。ThreadLocal是Handler机制能实现“每个线程都有自己的Looper”的关键。在Looper.prepare()中通过ThreadLocal.get()判断当前线程有没有Looper没有就new一个并set进去。主线程的Looper是ActivityThread在main方法里主动调用Looper.prepareMainLooper()和Looper.loop()创建的所以你才能在子线程里通过Handler去更新UI。笔试如果考这个你可以再补一句Handler构造时如果没指定Looper默认取当前线程的Looper因此在子线程new Handler前必须先prepare否则会抛RuntimeException。还有一个容易忽略的点MessageQueue的阻塞与唤醒机制。它利用Linux的epoll机制实现当队列没有消息时next()方法会阻塞在nativePollOnce不会空转浪费CPU当有消息需要处理时通过nativeWake唤醒。这个知识点在“如何实现高效的消息延迟发送”场景题里很有用比如你用Handler.postDelayed它并不是开一个定时器而是把消息按执行时间点插入到MessageQueue的合适位置再等待唤醒。理解了这个你就明白为什么“postDelayed的任务不一定会准点执行”——如果队列前面有其他耗时消息它的执行时间会被推迟。3. 应用层与实战场景考点2017年的校招笔试已经有了明显的“应用层导向”趋势卷子里开始出现技术选型、架构设计、性能优化这类实战性很强的内容。B卷在这个模块给我的感觉是不要求你写出多复杂的代码但要求你有清晰的工程判断力。3.1 网络框架选型与数据解析网络框架那时候正是群雄逐鹿的状态Volley、OkHttp、Retrofit、AsyncTask HttpURLConnection各有拥趸。笔试题目如果问“你用过哪些网络框架它们各自的优缺点是什么”那你要注意这题不是让你写作文而是考察你有没有根据业务场景做技术选型的能力。我当时是这样组织的Volley适合“请求多、数据量小”的场景自带内存缓存和请求调度但大文件下载和上传性能不太行。OkHttp底层基于Socket连接池和Okio支持HTTP/2和连接复用拦截器机制非常灵活适合做底层网络栈。Retrofit基于OkHttp封装通过注解和动态代理将接口定义转成HTTP请求配合RxJava可以实现非常优雅的响应式链式调用适合业务层使用。数据解析这块B卷大概率会考到JSON。你要搞清楚org.json、Gson、FastJSON、Jackson的底层区别。其中Gson通过反射将JSON映射成对象有缓存优化性能尚可FastJSON号称最快但它的AutoType特性在历史上出过反序列化漏洞即便2017年那次热门事件还没完全发酵这个问题也值得提Jackson则更注重稳定性和功能完备性。笔试题如果让你比较这些你就从性能、易用性、安全性三个维度展开会比较全面。另外网络这块还有一个必考细节HTTPS与证书校验。2017年Apple ATS政策已经推了几年Android也在逐渐收紧笔试大概率会有“如何防止抓包、如何保证信息安全”相关的题目。你至少要能说出来使用okhttp时可以通过CertificatePinner做证书绑定Certificate Pinning比只信任系统CA更安全不要忽略主机名验证HostnameVerifier对于用户输入要防止中间人攻击必须使用全链路HTTPS而不是只加密登录接口。这些都是工程经验比背书更能拿分。3.2 性能优化与内存泄漏的定位思路性能优化在B卷里通常以“线上卡顿怎么定位”或“App内存一直在涨可能有哪些原因”的方式出现。命题人不需要你真的修好过线上bug但希望你有排查问题的思路体系。内存泄漏的排查我通常分三步第一步用Android Studio的Memory Profiler抓取内存快照看哪些对象数量异常第二步用LeakCanary捕获泄漏对象它会自动分析引用链第三步结合MATMemory Analyzer Tool或Android Studio的Heap Dump分析GC Roots。笔试时你不需要写这么细但最好能表达出“工具定位代码分析”的组合思路。比如Activity泄漏先怀疑静态变量、单例、Handler、匿名线程再看有没有注册了系统服务没注销比如SensorManager、BroadcastReceiver这些都检查完再考虑是不是第三方SDK的锅。卡顿优化的答题思路与此类似。你要能从两个维度切入渲染层面和CPU层面。渲染层面看GPU Profile看看是Draw耗时还是Layout耗时是否因为过度绘制Overdraw、层级过深Hierarchy Viewer可以发现、主线程做了耗时操作IO、位图采样、JSON解析。CPU层面用Systrace或Perfetto看主线程的执行片断有没有长时间卡在主线程的Binder调用、锁等待、GC。这些工具名称你不一定全用过但至少要能说出来并且在笔试里体现出“按步骤排查不盲目优化”的工程素养。我自己遇到过的一个真实案例App首页在低端机上滑动不跟手最初以为是ListView的问题但切换成RecyclerView后依然卡。后来用Systrace一看发现主线程在执行一个BitmapFactory.decodeStream方法一次就解码了3张1920x1080的大图。我当时做头像展示直接把网络返回的大图塞进ImageView也没做压缩。解决方法是使用Glide或者自己写inSampleSize采样压缩。这类经验在笔试里写出来比回答“用Glide加载图片”要有说服力得多因为你能解释出“如果不做压缩即使用了Glide首次加载也会在主线程进行磁盘IO和图片解码”。3.3 自定义View与事件分发自定义View是Android开发进阶的必考项B卷在这个模块的考查角度通常是“测量、布局、绘制”三步曲以及“Touch事件分发机制”。这两块其实可以结合着考问你“在ViewGroup中如果onInterceptTouchEvent返回true子View的onTouchEvent还有机会执行吗”这种题本质上还是在考察事件分发。关于自定义View一定要答出onMeasure、onLayout、onDraw的顺序和各自职责。onMeasure决定这个View的尺寸模式下有三种EXACTLY、AT_MOST、UNSPECIFIED。其中EXACTLY对应match_parent或具体dpAT_MOST对应wrap_contentUNSPECIFIED一般只出现在ScrollView或RecyclerView的测量中。笔试如果让你画一个自定义控件的测量过程你需要写出MeasureSpec.getMode()和MeasureSpec.getSize()的解析逻辑并且在wrap_content时手动设置一个默认值否则自定义View的wrap_content会失效这是很多人踩过的坑。事件分发机制要理清三个核心方法dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。一条规律记住事件总是先从Activity - Window - DecorView - 外层ViewGroup - 内层View逐层向下传递先问“要不要拦截”再问“谁来消费”。如果所有View都不消费事件会原路返回给Activity的onTouchEvent。笔试里常考的陷阱是View.onTouchEvent在可点击状态下默认消费事件返回true但ViewGroup默认不拦截任何事件onInterceptTouchEvent返回false而RecyclerView和ScrollView这类可滚动容器在检测到手指滑动时会把事件拦截掉。如果你能把具体的分发场景讲出来比如“点击事件和滑动事件如何区分ACTION_CANCEL什么时候触发”就说明你真的理解它了。我当时备考自定义View时习惯把每个小细节都记成一个“判断题”比如“onDraw是发生在onLayout之后吗”——答案是大多数情况下是但如果你调用了requestLayout()只会触发onMeasure和onLayout不会触发onDraw而invalidate()则只会触发onDraw。这种细节题在笔试卷中简直是大杀器因为一旦考到不会的人只能瞎猜。4. 算法与设计模式算法题型在B卷里不会特别难但也不是送你分的。Linux的牛客网上当年分享的帖子来看常考的是字符串处理、链表操作、二叉树的遍历、动态规划入门题。设计模式则会结合Android源码来考比如问你“RecyclerView的Adapter用到什么模式”“EventBus是发布订阅模式吗”“Builder模式在AlertDialog中的应用”。4.1 常见算法题型与解题技巧2017年Android岗位的算法题难度基本对标LeetCode easy到medium级别。我当时刷题时发现最常出现的是链表反转、环形链表检测二叉树前序/中序/后序的非递归遍历数组去重、两数之和字符串反转、最长公共前缀简单的动态规划比如爬楼梯、最大子序和笔试如果给的是在线的IDE通常写Java或者Kotlin都行但要注意边界条件的判断。比如链表反转如果传入的head为null或者只有一个节点直接返回head数组类题目要提前判断数组的长度是否合法。我当时有个习惯写代码前先想好三个测试用例正常情况、边界情况、特殊情况这能在笔试中帮你少犯低级错误。在写链表反转这类题时切忌直接背模板要理解三指针前置节点、当前节点、后置节点的移动逻辑。你可以手动模拟一次比如链表1-2-3初始prenullcur1next2第一次循环cur.nextnullpre1cur2第二次循环cur.next1pre2cur3第三次循环cur.next2pre3curnull循环结束返回pre。把这个过程在草稿纸上画一遍比背十遍代码都管用。二叉树非递归遍历是易错题建议记住一个通用套路用栈模拟递归。中序遍历就是“一直往左走走不动了弹栈访问再往右走”前序遍历则是“入栈时访问一直往左走走不动了弹栈再往右走”后序遍历相对麻烦一点可以借助“先访问根再访问右再访问左”的反向思路或者用两个栈来处理。笔试时如果时间紧你也可以用递归先写一版有时候阅卷看的是思路而不是完全可运行的代码前提是你把递归的终止条件和逻辑写对。动态规划题在笔试卷里的出现频率很高因为代码量不大却能考察逻辑思维。爬楼梯就是典型的“斐波那契数列”问题dp[i]dp[i-1]dp[i-2]。笔试时不要急着写代码先把状态转移方程写出来再初始化边界条件dp[0]1dp[1]1或dp[1]2取决于题目设定最后再翻译成代码。这样即使代码写得不完美过程分已经拿到了。4.2 设计模式在Android中的应用设计模式在Android笔试中很少单独问你“单例模式有几种写法”而是喜欢把设计模式和具体源码结合起来。单例模式是必考项。笔试中你至少得写出双重检查锁DCL加上volatile关键字的写法并说明为什么要volatile——因为创建对象不是原子操作在JVM中会分解为分配内存、初始化对象、赋值引用三步如果不要volatile线程A可能在“赋值引用”完成后还没“初始化对象”时线程B就已经拿到这个引用并使用导致拿到半个对象。另外枚举单例虽然能防止反序列化但在Android中因为增加dex方法数和内存占用一般不建议在核心代码中使用静态内部类单例Initialization-on-demand holder idiom是最推荐的兼顾懒加载和线程安全。Builder模式在Android里的典型代表是AlertDialog和OkHttp的Request.Builder。笔试题如果问“Builder模式解决了什么问题”你要答出当一个类的构造函数参数过多且很多参数有默认值时直接构造对象会非常冗长且容易传错用Builder可以按需设置参数并提供链式调用提高可读性。这里有一个拓展点如果你有校验参数逻辑可以在Builder.build()方法里统一做而不用在构造函数里写一堆if判断。观察者模式在Android里的应用更是无处不在ListView/RecyclerView的Adapter.notifyDataSetChanged本质上就是通知观察者刷新LiveData、EventBus、RxJava也是观察者模式的不同实现。笔试如果谈到事件总线你最好能说出EventBus的优缺点优点是解耦、代码简洁缺点是调试困难、事件类型混乱后难以维护所以在大型项目中要慎用可以用RxJava的RxBus或者官方推荐的LiveData替代。5. 常见问题与答题技巧实录这部分我结合自己当年的备考经验和后来在面试别人的过程中总结出的一些共性问题做成一个速查表也算是给正在备考的同学一些参考。5.1 笔试中容易丢分的细节名词解释写不完整。Android的很多概念都有英文名面试官或阅卷人看到你只写中文不写英文或者英文拼写错误会觉得你不专业。比如Binder、MessageQueue、Looper、MeasureSpec、PackageManager这类词建议统一用英文原文后面用括号加中文解释。边界条件考虑不全。手写算法题的时候判空是第一步。但你光判断null还不够还要判断空字符串、空列表、长度为0的数组、两个指针重合等边界情况。我在笔试时吃过亏链表反转那道题我忘了处理head为null的情况运行直接空指针扣了很多分。多线程安全没有提及。场景设计题里如果涉及全局变量、缓存、数据库操作最好主动提一下线程安全性。你可以说“我会在关键方法上加synchronized或者使用ConcurrentHashMap”这样阅卷人会认为你有并发意识。尤其在ContentProvider操作中多线程同时读写数据库的问题几乎是必答点。没有分点作答。简答题最忌整段糊在一起阅卷人很难找到你的答题要点。我建议用序号分点每一点第一句话写核心结论后面是解释。比如问题是“如何避免Activity内存泄漏”你可以这样组织1. 使用静态内部类弱引用替代匿名内部类2. 在onDestroy中反注册BroadcastReceiver和取消网络请求3. 不使用static变量持有Activity或View的引用4. 单例模式下Context一律使用ApplicationContext。5.2 填空题与选择题的取舍2017年的笔试卷还有很多选择题和填空题这些题目的特点是比较碎容易“看着眼熟就是选不对”。比如选一个正确的说法四个选项可能都是看起来很有道理的“事实”但有一个前提条件不对。我的策略是先把明显错误的排除掉剩下两个犹豫时再回头审题看有没有“一定”“总是”“绝对”这类字眼。比如“一个Activity一定只有一个窗口”“Service总是在后台运行”“onPause之后一定会执行onStop”这三个说法都有反例所以它们基本都是错误选项。如果是填空题要注意单位、大小写、全称。比如内存单位是KB、MB还是BBinder是Android的进程间通信机制但不要写成“Binder机制是基于共享内存的”——严格来说Binder是基于内核态和用户态的内存拷贝不是共享内存。这类概念性问题容易在填空里翻车因为阅卷只看关键字是否匹配。版本差异题2017年尤其要注意Android 7.0和8.0的新特性。比如FileProvider、后台执行限制、Notification Channel、自适应图标、自动填充框架。选择题如果出现“Android 8.0之后如何启动前台Service”正确答案是必须调用startForegroundService()并在一段时间内调用startForeground()而不是传统的startService()。你了解这个分数就拿到了。5.3 备考时的三个小技巧第一搭建自己的“错题本”。不要只记录题目和答案要记录“我当时为什么错”“正确思路的关键转化点在哪里”。比如泛型边界问题我错是因为不知道上界? extends T只读下界? super T只写记录的时候就可以把“PECS原则”Producer Extends, Consumer Super写在旁边方便考前翻。第二用真题练手控制时间。笔试的时间往往很紧一套题大概90分钟到120分钟有时后面还有两道算法题。我的建议是拿到试卷先把所有题浏览一遍标记哪些题是必须拿分的基础概念题、简单算法题哪些是难题无从下手的复杂场景题。先把简单题快速解决难题留到最后。有合理的时间分配比在一道题上死磕要有用得多。第三把手写代码当“真代码”来写。在线笔试平台还好会自动补全缩进和括号但如果是纸质试卷你一定要写清楚缩进、括号匹配、类名和包名。字迹不用多好看但一定要工整可读。有时间的话用伪代码标明每一步的目的比如“// 1. 遍历数组统计每个字符出现次数”这样阅卷人在你代码不完整的时候也能看懂你的思路。6. 一点题外话笔试之外的准备校招笔试只是第一关通过之后还有一轮到两轮的技术面试。但笔试成绩往往会影响你被分配到哪个业务部门所以它对后续面试的走向还是有一定作用。我当年笔试完觉得发挥一般但好在面试时能用实际项目弥补。对于Android工程师岗来说笔试能过线的人基础通常差不到哪去。真正拉开差距的是你有没有真正写过一个完整的App有没有处理过崩溃、卡顿、兼容性这类“脏活累活”。所以我的建议是备考笔试的同时最好能抽时间做一个“有点复杂度”的个人项目哪怕只是一个仿微信朋友圈的应用也要把网络层、图片加载、多线程、消息推送、进程保活这些点都碰一遍。就算笔试没考到面试也能拿出来聊。就我自己而言我现在看别人的简历如果条目里写的都是“熟悉Android四大组件”“熟悉OkHttp”那说明这个候选人要么是刚入门要么是简历写得太水。我更希望看到的是“熟悉Android系统重要的性能分析工具并优化过多次UI卡顿问题”“有内存泄漏治理经验线上崩溃率从千分之一下降到万分之一”。这种有数据、有结果、有工具的经验才是笔试之外的真正加分项。所以在你刷往年的校招真题时别只满足于把题做对要多问自己一句“这个知识点我在自己的项目里有没有用过如果用过效果如何”把笔试题当成一次系统梳理知识体系的机会你就不会觉得它只是在为难你了。
返回列表