Android 第三方框架 相关

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)将响应数据解析为方法声明的返回值类型;

记忆:动态代理拦方法,注解转 Request,OkHttp 发请求,Converter 解响应。


2. 为什么 Retrofit 接口方法不能有重载?

  • 原因 :Retrofit 通过方法名 和注解 来唯一确定一个网络请求。重载方法同名但参数不同,动态代理在解析时无法区分,也无法根据参数类型推断注解含义,会导致歧义和实现复杂。
  • 替代:使用不同方法名,或将参数封装成对象。

记忆:重载同名难区分,注解解析易混淆,换不同名或对象。


3. Retrofit 是如何支持协程挂起函数的?

  • Continuation: 是 Kotlin 协程里的"续体对象",本质是一个回调接口,协程挂起时保存状态,恢复时从 Continuation 继续执行(唤醒协程 + 把结果/异常丢出去 + 让代码继续往下执行);

  • suspend 函数如何变成 Continuation?

    • Kotlin 编译器遇到 suspend 函数,会自动做 CPS (Continuation Passing Style 续体传递风格)转换。给函数自动加一个 Continuation 参数;
    • 函数不再直接返回结果,而是把结果交给 continuation.resumeWith();
  • Retrofit 依赖 Kotlin 编译器,通过 Continuation 把 OkHttp 异步回调结果交给 continuation.resumeWith();

    • 内部自动调度线程:IO 子线程请求,主线程恢复协程更新 UI;

4. 多个 BaseUrl 如何动态切换?

  • 注解 @Url:接口方法不传相对路径,直接传完整全路径 URL,灵活切换;
  • 多个 Retrofit 实例:不同 BaseUrl 单独创建 Retrofit + Service,隔离使用;
  • 全局配置转换器 :实现 BaseUrl 替换工厂,统一规则动态适配域名;
  • 拦截器动态替换:自定义 OkHttp 拦截器,拦截请求,动态修改 Request 的 host 和 path;

5. 如何实现请求缓存(无网络时返回缓存数据)?

  • 方案 :结合 OkHttp 的 缓存拦截器 和 网络拦截器 ,配合 CacheControl 策略。
  • 步骤 :
    1. 创建 OkHttp Cache 对象,设置缓存目录和大小。
    2. 添加自定义拦截器:若无网络,强制使用缓存(CacheControl.FORCE_CACHE);若有网络,根据缓存策略决定是否读缓存。
    3. 服务端需支持 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 队头阻塞;
  • OkHttp:OkHttp 默认支持 HTTP/2(如果服务器支持)。它会自动为同一主机使用一个连接进行多路复用,减少连接数,提升性能。

记忆:单连接并发行请求;OkHttp 自动升级 HTTP/2,复用连接。


10. 发生 SocketTimeoutException 时的重试机制?

  • 超时原因: 读写超时、网络波动、服务器响应慢;

  • OkHttp :自带默认重试机制,默认自动重试少量次数;

  • 自定义重试:

    • 自定义拦截器捕获 SocketTimeout 异常;
    • 通过循环 + 延迟,手动发起重试;
    • 设置最大重试次数、重试间隔;
  • 只对幂等 GET 请求重试,POST 谨慎避免重复提交;

记忆:Socket 读写超时触发该异常,OkHttp 内置简单重试;可自定义拦截器捕获异常,限制最大次数和间隔,对幂等 GET 做自动重试,POST 慎用。


11. 如何自定义 DNS(Domain 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 协程和 OkHttp,Coil 更轻量、更顺手;Glide 加载速度略快,但 Coil 的协程集成和 Compose 支持更好。

记忆口诀:Coil 全称协程加载器,Kotlin-first 轻量级;双层 LRU 内存磁盘,协程 suspend 自动取消;采样降 OOM,Bitmap 复用同 Glide;项目用协程选 Coil,Compose 支持更无敌。


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 中的缓存读取顺序):内存 → 磁盘 → 网络

  1. 从 ActiveResources 取:弱引用存储正在使用的图片,命中直接返回。
  2. 从 MemoryCache 取:LruCache,命中后移动到 ActiveResources。
  3. 从 DiskCache 取:先查 Resource Cache(已处理图),再查 Data Cache(原始数据)。
  4. 从网络/源头加载:以上都没有,开启 EngineJob 进行网络下载,解码后存入各级缓存reference:6。

缓存 Key 生成机制:根据图片 URL、宽高、变换参数等信息唯一标识,确保不同参数的同一图片单独缓存。

记忆口诀:活动引用正在用,Lru 内存暂存放,两级磁盘分形变与原始,BitmapPool 复用降 GC,缓存读取顺序:活动→内存→磁盘→网络。


15. EventBus 的原理、注解反射与线程调度

EventBus 通过发布/订阅 事件总线实现组件间通信,广泛用于 Android 模块解耦。

订阅、发布实现:

  • 订阅 :@Subscribe 注解标记订阅方法,方法必须有且仅有一个参数(事件类型)。EventBus 3.x 优先通过 APT(Annotation Processing Tool 注解处理器) 编译生成订阅者索引,避免反射;未配置或无法索引时回退到反射生成;
    • @Subscribe 标记订阅方法,指定线程模式、是否粘性、优先级;
  • 发布事件 :调用 post() 发送事件,根据事件类型从映射表找到所有订阅该事件的方法;
  • 遍历回调所有订阅方法,完成事件分发;

事件发布与线程调度:

  • post 发布事件 :根据事件类型在 subscriptionsByEventType 中找到所有订阅者,遍历调用 postToSubscription。
  • 线程调度 :@Subscribe(threadMode = ...) 支持 4 种模式:
    • POSTING:当前线程(发布线程)直接回调;
    • MAIN:切到主线程执行(通过 MainHandler 发送消息)。
    • BACKGROUND:切到后台线程(单线程池)。
    • ASYNC:异步线程池独立执行。
  • 粘性事件 :发送后缓存事件,后续注册的订阅者能收到之前已发送的粘性事件 。
    • postSticky 先缓存到 stickyEvents Map,后续注册粘性订阅者时立即收到。

记忆口诀:EventBus 发布/订阅模式,@Subscribe 标记订阅。APT 索引编译时生成,反射提速性能优。四种 ThreadMode 调度灵活,post 事件遍历分发,Sticky 存 Map 后注册也能接。


16. LeakCanary 的工作原理与内存泄漏检测

LeakCanary 内存泄漏检测通过 弱引用 + 引用队列 + 堆快照分析 实现,自动检测并报告内存泄漏。

详细工作原理:

  • 监听组件生命周期 :自动监听 Activity、Fragment、View、ViewModel 销毁时机(Application.registerActivityLifecycleCallbacks());
  • 标记待回收对象 :页面销毁后,将本该被 GC 回收的对象加入弱引用队列,关联唯一 Key;
  • 主动触发 GC:延迟一定时间后,手动触发 GC,等待虚拟机回收无用对象;
  • 判断是否泄漏 :检查弱引用队列,对象未被回收,说明存在强引用持有,判定内存泄漏;
  • 堆快照分析 :生成 hprof 堆文件,解析引用链,找出是谁持有导致对象无法回收;
  • 展示泄漏:在桌面弹窗展示泄漏位置、引用链路,方便定位修复;

检测原理:当 JVM 进行垃圾回收时,如果对象只有弱引用存在,该对象会被回收,弱引用进入引用队列;反之若引用队列中没有该弱引用,说明对象仍有其他强引用持有,判定为内存泄漏。

常见配置 :DebuggerControl(调试模式禁用检测)、watchDurationMillis(5s 等待 GC 窗口)、ReferenceMatcher 用于忽略系统已知的泄漏(如某些 Android 版本 View 的 mContext 泄露)。

记忆口诀:弱引用绑定观察对象,GC 后查引用队列判泄漏。堆转储分析引用链,报告分类应用或库。ContentProvider 自动初始化,Activity 泄漏自动检测。


相关推荐
晚风叙码1 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程2 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程4 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程6 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程6 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程6 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓6 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android
传奇开心果编程6 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer
supabc1237 小时前
Celium:连接 Windows、Mac、Linux 与 Android,让远程访问和设备管理更简单
android·linux·windows·macos·远程访问·网络管理·celium
Dovis(誓平步青云)7 小时前
导览音频切换太快,旧讲解不能覆盖新展品
android·前端·javascript·ecmascript·音视频·宠物