小米Android开发面试全记录:Jetpack+性能优化+系统级开发全考察
3年Android开发经验,详细复盘小米三轮技术面试,涵盖Kotlin协程、Jetpack全家桶、性能优化、内存泄漏排查、Binder原理、插件化框架等核心考点
背景介绍
先说下我的情况,211本科计算机专业毕业,在一家中型互联网公司做了三年Android开发。虽然不是大厂出身,但项目经验还算丰富——从0到1做过两个App,也做过SDK开发。小米一直是我的Dream Company之一,毕竟是做MIUI起家的,Android开发的技术深度肯定不差。而且小米现在在造车,Android开发在车机端也有应用场景,感觉发展空间很大。
投简历是在小米招聘官网投的,大概五天后收到了HR的电话,约了一面时间。整个流程三周左右,三轮技术面+一轮HR面。下面详细说说每轮面试的情况。
面试流程复盘
一面:Kotlin+Jetpack(约1小时)
一面面试官是个看起来很干练的工程师,开场先让我简单介绍了一下工作经历,然后直接开始技术问答。
第一个问题就让我有点紧张:Kotlin的协程和Java的线程有什么区别?协程的挂起是怎么回事?我从轻量级、非阻塞、协作式调度几个角度做了对比,然后讲了suspend关键字和状态机的关系——编译器会把suspend函数转换成状态机,通过Continuation传递来实现的。面试官追问:withContext和async的区别?在什么场景下用哪个?我说withContext是串行切换调度器,async是并行执行并等待结果,需要并行多个任务时用async,需要切换线程执行单个任务时用withContext。
Jetpack部分问得很细:ViewModel的生命周期是怎样的?为什么Configuration Change时ViewModel不会销毁?我从ViewModelStore的角度解释,ViewModel存在Activity的ViewModelStore中,而Configuration Change时Activity虽然会重建,但ViewModelStore会被保留。面试官追问:ViewModelStore是怎么被保留的?这个我答得不太好,只说了通过NonConfigurationInstances机制,但具体实现细节记不太清了。面试官提示了一下是ActivityThread的retainNonConfigurationInstances方法,我表示确实没看到这一层。
还问了:Room数据库的Migration机制?、Navigation组件的深层链接怎么实现?、DataStore和SharedPreferences的区别?这些都是Jetpack的常见考点,我基本都答上来了。
代码题是:用Kotlin实现一个带缓存的图片加载框架的核心逻辑,要求支持内存缓存和磁盘缓存。这道题考察的是设计能力,我用了LruCache做内存缓存,磁盘缓存用DiskLruCache,加载流程是内存→磁盘→网络的三级缓存。面试官让我写了内存缓存的核心代码,包括LruCache的sizeOf方法重写和缓存淘汰策略。
二面:性能优化+内存泄漏(约1.5小时)
二面是个做性能优化的专家,一上来就问我:你在项目中做过哪些性能优化?我从启动优化、布局优化、内存优化三个方面讲了我们的实践。
启动优化那块,我讲了我们用systrace分析冷启动耗时,发现Application的onCreate里做了太多初始化,后来用有向无环图做任务调度,把初始化任务按依赖关系并行化,冷启动时间从3秒降到了1.5秒。面试官追问:有向无环图的拓扑排序怎么实现?如果存在循环依赖怎么办?我说用BFS实现,循环依赖在构建图的时候检测,如果发现有入度始终不为0的节点就说明存在循环。
内存泄漏部分是重点:常见的内存泄漏场景有哪些?怎么排查?我从静态变量持有Activity引用、内部类持有外部类引用、Handler的Message未移除、注册的监听器未反注册几个场景讲起,排查工具讲了LeakCanary和Android Studio的Memory Profiler。面试官追问:LeakCanary的原理是什么?它是怎么自动检测内存泄漏的?我讲了WeakReference+ReferenceQueue的机制,以及GC后如果WeakReference仍然存在引用链就说明有泄漏。
他还问了一个很有深度的问题:如果App在低端机上出现频繁GC导致卡顿,你怎么排查和优化?我说先用Memory Profiler看内存分配情况,找出分配频率最高的对象,然后看能否减少分配——比如用对象池复用、避免在循环中创建对象、用基本类型代替包装类型。面试官追问:对象池的实现有什么要注意的?我说要注意池的大小控制,避免池本身成为内存泄漏源,还要注意多线程安全。
代码题是:实现一个简单的对象池,支持泛型,要求线程安全。我用ConcurrentLinkedQueue做对象存储,用AtomicInteger控制池大小,写了一个泛型对象池。面试官让我考虑一下对象回收时的状态重置问题,我说可以在回收时调用一个reset方法来清理对象状态。
三面:系统级开发+项目深挖(约1.5小时)
三面是个资深架构师,问题更加宏观和系统化。
他先问:你对Android的进程间通信了解多少?Binder的原理是什么?我从Binder的C/S架构讲起,说到ServiceManager、Binder驱动、内存映射,以及一次拷贝的高效性。他追问:Binder和Socket、管道、共享内存等其他IPC方式相比有什么优势?我对比了性能、安全性、易用性几个维度,Binder在性能上仅次于共享内存,但安全性更好。
然后是项目深挖环节,他让我讲一个最有挑战的项目。我选了之前做的插件化框架开发——我们用Hook Instrumentation的方式实现Activity的插件化加载。他问的问题非常刁钻:Hook Instrumentation的时机是什么?怎么保证Hook的稳定性?、插件中的资源怎么加载?资源ID冲突怎么解决?、Android 9.0之后对反射的限制怎么绕过?
资源ID冲突那块我答得不太好,我们当时的方案是给插件的资源ID加一个偏移量来避免冲突,但面试官说这种方案在插件数量多的时候不够灵活,建议了解一下AAPT2的资源ID分段机制。Android 9.0的反射限制那块,我讲了用元反射绕过——通过反射获取反射的setAccessible方法来突破限制,但面试官说这个方案在高版本上可能失效,让我关注Android最新的限制策略。
最后聊了大概20分钟的技术方向,面试官介绍了小米在Android系统级开发上的一些探索,包括他们自研的MIUI优化框架和车机端的Android系统定制,听起来确实很有技术深度。
真题汇总
1. Kotlin协程和Java线程的区别?协程挂起的原理?
2. withContext和async的区别和使用场景?
3. ViewModel的生命周期和ViewModelStore保留机制?
4. 实现带缓存的图片加载框架核心逻辑
5. 冷启动优化方案?有向无环图任务调度?
6. 常见内存泄漏场景和排查方法?LeakCanary原理?
7. 频繁GC导致卡顿的排查和优化?
8. 实现线程安全的泛型对象池
9. Binder原理?和其他IPC方式的对比?
10. 插件化框架的实现?资源ID冲突解决?
心得建议
第一,Kotlin必须精通。小米的Android开发全面使用Kotlin,面试中Kotlin相关的题目占比很大。尤其是协程,不能只停留在会用launch和async的层面,要理解底层的状态机实现。
第二,Jetpack全家桶要熟悉。ViewModel、Room、Navigation、DataStore这些组件的原理和使用场景都要掌握,面试中会从使用问到原理。
第三,性能优化要有实战。小米特别看重性能优化能力,启动优化、内存优化、卡顿优化都要有实际经验。光知道工具名字不行,得能讲出具体的优化过程和效果数据。
第四,系统级知识是加分项。如果你了解Binder、AMS、PMS这些系统级知识,面试官会非常感兴趣。尤其是做系统级开发的岗位,这些是必考内容。
第五,项目经验要有深度。小米面试官很在意你是否真正理解项目的技术细节,而不只是用了什么框架。每个技术选型的原因、踩过的坑、做过的优化,都要能说清楚。
FAQ
Q:小米Android开发的工作强度如何?
A:面试时了解到MIUI版本迭代期加班较多,但平时节奏还行。相比互联网大厂,小米的工作强度算是中等偏上。
Q:对Kotlin有硬性要求吗?
A:基本是硬性要求,小米Android开发全面使用Kotlin,面试中Kotlin题目占比很大。
Q:面试结果多久出?
A:我是一面后4天约二面,二面后5天约三面,三面后一周出结果,整体大概三周。
Q:学历要求?
A:Android开发岗本科就行,但985/211优先。有扎实的项目经验比学历更重要。
Q:薪资水平?
A:3年Android经验,月薪大概在22-32k之间,总包在35-50w左右。小米的薪资在手机厂商里算不错的,而且股票激励比较大方。