上篇初级聊完Activity和RecyclerView,这篇进入美团中级。中级面试考框架理解——不是问"你会用Retrofit吗",而是问"Retrofit的动态代理怎么工作的?RxJava的flatMap和map什么区别?Glide的三级缓存怎么设计的?"
美团中级Android要求能独立负责业务模块,对常用框架的源码有一定了解。面试官看你的技术深度够不够从"使用者"进阶到"理解者"。
今天8道题覆盖美团中级核心考点。
Q1:Retrofit的动态代理原理?
核心流程:接口注解描述HTTP请求 → Retrofit.create返回动态代理对象 → 调方法时代理拦截 → 解析注解拼Request → OkHttp发请求 → Converter解析Response。
动态代理:Proxy.newProxyInstance创建代理。invoke里通过ServiceMethod把方法注解解析成HTTP请求(URL/参数/Header)。
CallAdapter:把OkHttp的Call转成其他类型。RxJava2CallAdapter转Observable,CoroutineCallAdapter转Deferred。
追问:Retrofit和OkHttp什么关系?Retrofit是OkHttp的上层封装——OkHttp负责底层网络通信,Retrofit负责把接口方法转成HTTP请求。Retrofit底层用OkHttp的OkHttpClient发请求。
Q2:RxJava的map和flatMap区别?
map:一对一转换。Observable<T> → map → Observable<R>。输入一个元素输出一个元素。类型转换用map。
flatMap:一对多转换再合并。Observable<T> → flatMap → 每个元素生成一个Observable → 合并成一个Observable。适合嵌套异步——第一个请求返回结果用结果发起第二个请求。
flatMap vs concatMap:flatMap不保证顺序(内部Observable并发执行),concatMap保证顺序(前一个完成才开始下一个)。需要顺序保证时用concatMap。
追问:RxJava的subscribeOn和observeOn区别?subscribeOn指定上游(数据生产)在哪个线程,observeOn指定下游(数据消费)在哪个线程。subscribeOn只能调一次(第一次有效),observeOn可以调多次(切换线程)。
Q3:Glide的三级缓存怎么设计?
ActiveResources(弱引用缓存):正在显示的图片。WeakReference持有Bitmap,显示时从ActiveResources取。图片不再显示时弱引用自动释放。
MemoryCache(LruCache):不在显示但最近用过的图片。LruCache按maxSize淘汰最久未用的。默认maxSize = App可用内存的1/8。
DiskCache(磁盘缓存):原图(DATA_CACHE)或转换后图(RESOURCE_CACHE)。DiskLruCache实现,默认250MB。
加载流程:先查ActiveResources(命中直接返回)→ 查MemoryCache(命中移到ActiveResources返回)→ 查DiskCache(命中解码移到MemoryCache返回)→ 网络请求(下载到DiskCache,解码到MemoryCache,显示)。
追问:Glide怎么根据ImageView大小加载合适分辨率?override(width, height)指定目标尺寸。不指定时Glide用View的getWidth/getHeight(View没measure完会注册监听等measure完再加载)。避免加载大图到小ImageView浪费内存。
Q4:LiveData的setValue和postValue区别?
setValue:必须主线程调。直接修改数据并通知观察者。连续调多次setValue只通知末次(合并机制)。
postValue:任意线程可调。内部存到pendingData字段post到主线程处理。连续调多次postValue只保留末次的值(覆盖之前的)。
LiveData的优势:生命周期感知——Activity/Fragment destroy后自动取消观察不会内存泄漏。数据粘性问题——新observe的观察者会立即收到最新数据(不像EventBus要加sticky参数)。
追问:LiveData的缺点?只能在主线程观察(observe内部检查线程)。背压不支持——数据产生太快观察者处理不过来会丢数据。大数据量场景推荐StateFlow/SharedFlow替代。
Q5:ViewModel为什么能存活?配置变更时发生了什么?
配置变更(屏幕旋转/语言切换):Activity销毁重建,普通成员变量丢失。ViewModel存在ViewModelStore里,由NonConfigurationInstances持有(不受配置变更影响)。
流程:Activity onDestroy时检查isChangingConfigurations——配置变更则保留ViewModelStore。新Activity重建时拿回ViewModelStore,ViewModel实例还在。
onCleared:Activity真正销毁(非配置变更)时调ViewModelStore.clear() → ViewModel.onCleared()。在此取消网络请求释放资源。
追问:ViewModel里能持有Activity/View引用吗?不能。ViewModel存活时间比Activity长(配置变更时Activity销毁但ViewModel还在),持有引用会内存泄漏。需要Context用AndroidViewModel的Application引用。
Q6:Retrofit+RxJava+ViewModel怎么配合?
典型MVVM:View → ViewModel → Repository → Retrofit。
Repository:封装数据获取逻辑。先查缓存没有走网络。返回LiveData给ViewModel。
ViewModel:持有LiveData调Repository获取数据,数据变化setValue通知View。配置变更时数据不丢。
View:observe LiveData自动更新UI,不用手动处理生命周期。
追问:Repository解耦数据源和业务逻辑。ViewModel不关心数据从哪来。方便测试(Mock Repository)和切换数据源。
Q7:DataBinding和ViewBinding区别?
ViewBinding:自动生成Binding类访问View。编译期生成,无反射无注解处理,编译快。只替代findViewById。
DataBinding:支持双向绑定和布局表达式,数据变化自动更新View。功能强但编译慢、调试困难。
选择:Google推荐新项目用ViewBinding。DataBinding适合表单页面。美团项目大部分用ViewBinding。
Q8:美团的技术栈有什么特点?
网络层:Retrofit+OkHttp+RxJava是标准配置。部分新模块用Kotlin Coroutines替代RxJava。
架构:MVVM为主。ViewModel+LiveData+Repository三层架构。老模块还有MVP。
图片:Glide为主。部分场景用Fresco(大图/渐进式加载)。
路由:自研路由框架(类似ARouter),组件间通过路由跳转。
面试Tips:美团中级Retrofit考动态代理原理和CallAdapter机制。RxJava考map/flatMap区别和线程切换。Glide考三级缓存流程。LiveData考setValue/postValue和生命周期感知。ViewModel考配置变更存活原理。准备时重点理解"框架为什么这么设计"而不仅是"框架怎么用"。
下一篇进入美团高级——OkHttp源码、Okio源码、LeakCanary原理、BlockCanary原理。
项目里用MVVM的同学评论区聊聊,你们Repository怎么设计的?
本系列连载中,关注不迷路,下一篇:美团高级Android工程师面试真题
系列简介:Android大厂面经连载,覆盖字节跳动、腾讯、阿里、美团等40+企业,从初级到架构师全岗位覆盖。每篇文章包含真实面试题+详细答案+代码示例,帮你拿到大厂Offer。