1. Retrofit 的工作原理如何通过动态代理将接口注解转换为网络请求Retrofit 是基于 OkHttp 封装的 RESTful 网络请求框架本身不做实际的网络请求只负责创建动态代理、接口解析、参数封装、构建请求对象、解析响应数据最终交给 OkHttp 发送请求。原理先定义网路请求接口用注解GET、POST、Path、Query等标记请求方式、路径参数等然后调用retrofit.create(Servcie::class.java)通过动态代理Proxy.newProxyInstance的方式生成接口的实现类调用接口方法时代理拦截该方法解析注解、参数、返回类型等InvocationHandler.invoke封装成 ServiceMethod 对象ServiceMethod 对象会根据实际传入的参数生成OkHttp 的 Request 对象由OkHttpCall执行网络请求最后通过 Converter如 Gson将响应数据解析为方法声明的返回值类型记忆动态代理拦方法注解转 RequestOkHttp 发请求Converter 解响应。2. 为什么 Retrofit 接口方法不能有重载原因Retrofit 通过方法名和注解来唯一确定一个网络请求。重载方法同名但参数不同动态代理在解析时无法区分也无法根据参数类型推断注解含义会导致歧义和实现复杂。替代使用不同方法名或将参数封装成对象。记忆重载同名难区分注解解析易混淆换不同名或对象。3. Retrofit 是如何支持协程挂起函数的Continuation是 Kotlin 协程里的“续体对象”本质是一个回调接口协程挂起时保存状态恢复时从 Continuation 继续执行唤醒协程 把结果/异常丢出去 让代码继续往下执行suspend函数如何变成 ContinuationKotlin 编译器遇到suspend函数会自动做CPSContinuation Passing Style 续体传递风格转换。给函数自动加一个Continuation 参数函数不再直接返回结果而是把结果交给continuation.resumeWith()Retrofit 依赖 Kotlin 编译器通过 Continuation 把 OkHttp 异步回调结果交给continuation.resumeWith()内部自动调度线程IO 子线程请求主线程恢复协程更新 UI4. 多个 BaseUrl 如何动态切换注解 Url接口方法不传相对路径直接传完整全路径 URL灵活切换多个 Retrofit 实例不同 BaseUrl 单独创建 Retrofit Service隔离使用全局配置转换器实现BaseUrl替换工厂统一规则动态适配域名拦截器动态替换自定义 OkHttp 拦截器拦截请求动态修改 Request 的 host 和 path5. 如何实现请求缓存无网络时返回缓存数据方案结合 OkHttp 的缓存拦截器和网络拦截器配合CacheControl策略。步骤创建 OkHttpCache对象设置缓存目录和大小。添加自定义拦截器若无网络强制使用缓存CacheControl.FORCE_CACHE若有网络根据缓存策略决定是否读缓存。服务端需支持Cache-Control响应头。Retrofit通过 OkHttp 的Cache和拦截器实现对业务层透明。记忆OkHttp 缓存 拦截器无网强制缓存有网按策略走。6. OkHttp 的拦截器机制Interceptor Chain责任链模式处理请求和响应机制OkHttp 采用责任链模式多个拦截器形成链式调用通过Chain.proceed把请求交给下一个拦截器每个拦截器都可对请求进行处理自定义拦截器可添加应用拦截器最早执行或网络拦截器在连接后执行监控网络层数据传输常见内置拦截器retryAndFollowUpInterceptor失败和重定向拦截器。当请求内部抛出异常时判定是否需要重试当响应结果是3xx重定向时构建新的请求并发送请求BridgeInterceptor应用层和网络层的桥接拦截器。主要工作是请求添加cookie添加固定的header比如Host、Content-Length、Content-Type、User-Agent等等然后保存响应结果的cookie如果响应使用gzip压缩过则还需要解压CacheInterceptor缓存拦截器。如果命中缓存则不发起网络请求ConnectInterceptor连接拦截器。内部会维持一个连接池主要负责TCP连接包括连接复用、创建连接三次握手、释放连接以及创建连接上的socket流CallServerInterceptor请求拦截器。在前置准备工作完成后真正发起网络请求记忆拦截器连成链proceed 递进各司其职应用优先网络后。7. 谈谈网络请求中的拦截器应用拦截器 vs 网络拦截器区别类型特点应用拦截器addInterceptor最先执行只执行一次不关心重定向、重试多次请求网络拦截器addNetworkInterceptor每次重试、重定向都会重复执行监控网络层数据传输、连接建立的过程记忆应用拦截器最早一次网络拦截器在连接后可多次。8. OkHttp 如何支持 HTTPS基本握手与验证基于SSL/TLS协议建立加密连接SSL Secure Sockets Layer 安全套接层TLS Transport Layer Security 传输层安全默认信任系统内置的合法 CA 根证书完成证书链校验进行域名校验防止中间人攻击握手完成后使用对称加密传输数据保证传输安全自定义证书配置如自签名证书可自定义SSLSocketFactory和HostnameVerifier以信任本地自定义证书。仅测试环境下可忽略证书校验不推荐生产环境使用。证书锁定Certificate Pinning通过CertificatePinner限制只信任特定公钥或证书进一步防止中间人攻击。记忆基于 SSL/TLS 握手加密默认校验 CA 合法证书链与域名支持自定义证书、双向认证加密传输防窃听和中间人攻击。9. 什么是 HTTP/2 的多路复用OkHttp 如何利用它多路复用同一个 TCP 连接可以同时跑多个 HTTP 请求不用排队不会阻塞请求按帧拆分交错传输互不阻塞解决 HTTP1.1 队头阻塞OkHttpOkHttp 默认支持 HTTP/2如果服务器支持。它会自动为同一主机使用一个连接进行多路复用减少连接数提升性能。记忆单连接并发行请求OkHttp 自动升级 HTTP/2复用连接。10. 发生 SocketTimeoutException 时的重试机制超时原因读写超时、网络波动、服务器响应慢OkHttp自带默认重试机制默认自动重试少量次数自定义重试自定义拦截器捕获 SocketTimeout 异常通过循环 延迟手动发起重试设置最大重试次数、重试间隔只对幂等 GET 请求重试POST 谨慎避免重复提交记忆Socket 读写超时触发该异常OkHttp 内置简单重试可自定义拦截器捕获异常限制最大次数和间隔对幂等 GET 做自动重试POST 慎用。11. 如何自定义 DNSDomain Name System 域名系统实现 OkHttp 的Dns接口重写lookup()方法自定义域名解析逻辑本地静态映射、阿里 / 腾讯公共 DNS、IP 直连构建 OkHttpClient 时通过dns()注入自定义 DNS作用绕过系统 DNS、防 DNS 劫持、域名 IP 直连、智能调度切换 IP。记忆实现 OkHttp Dns 接口重写 lookup 方法自定义域名解析规则构建 OkHttp 注入实现 IP 直连、防劫持、自定义公共 DNS。12. 说说 ViewBinding 和 DataBinding 的区别DataBinding 是如果实现数据和 UI 的双向绑定核心区别ViewBinding只做视图绑定自动生成布局对应绑定类直接引用 XML 控件 ID无数据绑定、无 MVVM轻量、编译快、无注解、仅替代 findViewById不支持表达式、不支持双向绑定。DataBinding兼顾视图绑定 数据绑定 MVVM布局内嵌layout、data绑定实体类支持表达式、单向 / 双向绑定、事件绑定编译慢、复杂度高适合正式 MVVM 项目DataBinding 双向绑定实现原理布局中使用{}语法声明双向绑定编译器编译时会为每个布局生成绑定辅助类 XXLayoutBinding数据实体继承BaseObservable字段变化时主动通知 UI 刷新UI 控件编辑变化自动反向同步到数据模型底层借助监听器 反射 / 注解生成代码实现 UI ↔ 数据 自动同步。ViewBinding 可视为 DataBinding 的子集如果只需视图绑定功能建议优先使用 ViewBinding。13. Coil 图片加载库的特点与协程实现Coil 全称Coroutine Image Loader是 Kotlin-first 的图片加载库纯 Kotlin 编写基于 Kotlin 协程构建。Coil 核心特点对比 Glide轻量级API 更简洁优雅适配 Kotlin 项目包体积增量远小于 Glide无多余依赖但比 Glide 加载慢些挂起函数异步加载通过挂起函数实现每个图片请求通过suspend fun execute()返回 ImageResult无需回调。替代 Glide 的线程池 Handler更轻量协程是 Kotlin 提供的轻量级并发模型挂起函数是实现协程挂起与恢复的核心机制二者配合实现非阻塞式异步编程。生命周期感知利用CoroutineScope绑定 Activity/Fragment 销毁自动取消请求避免内存泄漏和无效网络缓存机制与 Glide 一致的双层 LRU内存缓存存 Bitmap 对象磁盘缓存存原始数据但 API 更简化Jetpack Compose 支持声明式 API原生适配 Compose 项目线程调度通过setDecodingDispatcher、setFetcherDispatcher分别控制解码和网络/磁盘 IO 的调度器无需手动切换线程。流水线处理缓存查询、网络下载、解码全部在协程中串行排队线程开销低于传统线程池。自动暂停/取消滑动列表时自动暂停未显示的请求节省网络和 CPU。内存安全自动采样策略、Bitmap 复用降低 OOM 风险。对比 Glide若项目大量使用 Kotlin 协程和 OkHttpCoil 更轻量、更顺手Glide 加载速度略快但 Coil 的协程集成和 Compose 支持更好。记忆口诀Coil 全称协程加载器Kotlin-first 轻量级双层 LRU 内存磁盘协程 suspend 自动取消采样降 OOMBitmap 复用同 Glide项目用协程选 CoilCompose 支持更无敌。14. Glide 的完整加载流程与缓存机制三级缓存Glide 使用ActiveResources活动资源弱引用 MemoryCache内存缓存 LruCache DiskCache磁盘缓存 LruCache。ActiveResources存储当前正在使用的图片弱引用界面不展示后移到 MemoryCache。读取优先级最高活动缓存解决 Lru 缓存时存在的弊端问题。MemoryCache存储最近释放的图片LruCache图片离开界面但还在内存缓存中下次加载直接复用。DiskCache分为Resource Cache形变后缓存如缩放宽高和Data Cache源数据原始缓存以文件形式存储在应用的私有目录下采用 Lru 算法。LRU 全称最近最少使用算法优先淘汰长时间未使用的数据底层基于 LinkedHashMap开启访问有序模式。核心机制每次 get/put 访问元素会将当前元素移至队列头部长期不访问的元素会逐步挤到队列尾部缓存达到设定阈值时自动移除尾部最少使用元素加载流程Engine.load 中的缓存读取顺序内存 → 磁盘 → 网络从 ActiveResources 取弱引用存储正在使用的图片命中直接返回。从 MemoryCache 取LruCache命中后移动到 ActiveResources。从 DiskCache 取先查 Resource Cache已处理图再查 Data Cache原始数据。从网络/源头加载以上都没有开启 EngineJob 进行网络下载解码后存入各级缓存[reference:6]。缓存 Key 生成机制根据图片 URL、宽高、变换参数等信息唯一标识确保不同参数的同一图片单独缓存。记忆口诀活动引用正在用Lru 内存暂存放两级磁盘分形变与原始BitmapPool 复用降 GC缓存读取顺序活动→内存→磁盘→网络。15. EventBus 的原理、注解反射与线程调度EventBus 通过发布/订阅事件总线实现组件间通信广泛用于 Android 模块解耦。订阅、发布实现订阅Subscribe注解标记订阅方法方法必须有且仅有一个参数事件类型。EventBus 3.x 优先通过APTAnnotation Processing Tool 注解处理器编译生成订阅者索引避免反射未配置或无法索引时回退到反射生成Subscribe标记订阅方法指定线程模式、是否粘性、优先级发布事件调用post()发送事件根据事件类型从映射表找到所有订阅该事件的方法遍历回调所有订阅方法完成事件分发事件发布与线程调度post发布事件根据事件类型在subscriptionsByEventType中找到所有订阅者遍历调用postToSubscription。线程调度Subscribe(threadMode ...)支持 4 种模式POSTING当前线程发布线程直接回调MAIN切到主线程执行通过MainHandler发送消息。BACKGROUND切到后台线程单线程池。ASYNC异步线程池独立执行。粘性事件发送后缓存事件后续注册的订阅者能收到之前已发送的粘性事件。postSticky先缓存到stickyEventsMap后续注册粘性订阅者时立即收到。记忆口诀EventBus 发布/订阅模式Subscribe 标记订阅。APT 索引编译时生成反射提速性能优。四种 ThreadMode 调度灵活post 事件遍历分发Sticky 存 Map 后注册也能接。16. LeakCanary 的工作原理与内存泄漏检测LeakCanary 内存泄漏检测通过弱引用 引用队列 堆快照分析实现自动检测并报告内存泄漏。详细工作原理监听组件生命周期自动监听Activity、Fragment、View、ViewModel销毁时机Application.registerActivityLifecycleCallbacks()标记待回收对象页面销毁后将本该被 GC 回收的对象加入弱引用队列关联唯一 Key主动触发 GC延迟一定时间后手动触发 GC等待虚拟机回收无用对象判断是否泄漏检查弱引用队列对象未被回收说明存在强引用持有判定内存泄漏堆快照分析生成 hprof 堆文件解析引用链找出是谁持有导致对象无法回收展示泄漏在桌面弹窗展示泄漏位置、引用链路方便定位修复检测原理当 JVM 进行垃圾回收时如果对象只有弱引用存在该对象会被回收弱引用进入引用队列反之若引用队列中没有该弱引用说明对象仍有其他强引用持有判定为内存泄漏。常见配置DebuggerControl调试模式禁用检测、watchDurationMillis5s 等待 GC 窗口、ReferenceMatcher用于忽略系统已知的泄漏如某些 Android 版本 View 的 mContext 泄露。记忆口诀弱引用绑定观察对象GC 后查引用队列判泄漏。堆转储分析引用链报告分类应用或库。ContentProvider 自动初始化Activity 泄漏自动检测。