【Android面试】OkHttp & Retrofit 专题

文章目录

  • [一、OkHttp 相关(源码+设计模式+核心用法)](#一、OkHttp 相关(源码+设计模式+核心用法))
    • [1. OkHttp 的核心架构是什么?核心组件(Dispatcher、Interceptor、Call、RealCall)的职责分别是什么?](#1. OkHttp 的核心架构是什么?核心组件(Dispatcher、Interceptor、Call、RealCall)的职责分别是什么?)
    • [2. OkHttp 的拦截器(Interceptor)机制原理,应用拦截器与网络拦截器的区别,如何自定义拦截器?](#2. OkHttp 的拦截器(Interceptor)机制原理,应用拦截器与网络拦截器的区别,如何自定义拦截器?)
    • [3. OkHttp 中 Dispatcher 的工作原理,如何实现请求的并发控制、异步请求的分发与回调?](#3. OkHttp 中 Dispatcher 的工作原理,如何实现请求的并发控制、异步请求的分发与回调?)
    • [4. OkHttp 的连接池(ConnectionPool)实现原理,连接复用、空闲连接回收的机制是什么?](#4. OkHttp 的连接池(ConnectionPool)实现原理,连接复用、空闲连接回收的机制是什么?)
    • [5. OkHttp 如何处理 HTTP 缓存?缓存策略(CacheStrategy)的核心逻辑,缓存过期、缓存失效的判断规则?](#5. OkHttp 如何处理 HTTP 缓存?缓存策略(CacheStrategy)的核心逻辑,缓存过期、缓存失效的判断规则?)
    • [6. OkHttp 中用到了哪些设计模式?(至少列举3种,结合源码场景说明)](#6. OkHttp 中用到了哪些设计模式?(至少列举3种,结合源码场景说明))
    • [7. OkHttp 如何实现异步请求的回调切换(子线程→主线程)?与 Handler、Looper 的关联是什么?](#7. OkHttp 如何实现异步请求的回调切换(子线程→主线程)?与 Handler、Looper 的关联是什么?)
    • [8. OkHttp 对 HTTPS 的支持原理,SSL 证书校验的流程,如何自定义证书校验逻辑?](#8. OkHttp 对 HTTPS 的支持原理,SSL 证书校验的流程,如何自定义证书校验逻辑?)
    • [9. RealCall 的 execute() 和 enqueue() 方法区别,底层执行流程有何不同?](#9. RealCall 的 execute() 和 enqueue() 方法区别,底层执行流程有何不同?)
  • [二、Retrofit 相关(源码+设计模式+核心用法)](#二、Retrofit 相关(源码+设计模式+核心用法))
    • [1. Retrofit 的核心工作流程,从接口定义到发起网络请求的完整链路是什么?](#1. Retrofit 的核心工作流程,从接口定义到发起网络请求的完整链路是什么?)
    • [2. Retrofit 如何将接口方法(如 @GET、@POST)转化为实际的 HTTP 请求?动态代理的应用原理?](#2. Retrofit 如何将接口方法(如 @GET、@POST)转化为实际的 HTTP 请求?动态代理的应用原理?)
    • [3. Retrofit 的 Converter 转换器原理,如何自定义 Converter(如解析自定义格式数据)](#3. Retrofit 的 Converter 转换器原理,如何自定义 Converter(如解析自定义格式数据))
    • [4. Retrofit 的 CallAdapter 适配器原理,与 OkHttp Call 的关联,如何自定义 CallAdapter(如适配 RxJava、Coroutine)](#4. Retrofit 的 CallAdapter 适配器原理,与 OkHttp Call 的关联,如何自定义 CallAdapter(如适配 RxJava、Coroutine))
    • [5. Retrofit 中用到了哪些设计模式?(结合源码,重点说明动态代理、工厂模式、适配器模式)](#5. Retrofit 中用到了哪些设计模式?(结合源码,重点说明动态代理、工厂模式、适配器模式))
    • [6. Retrofit 如何与 OkHttp 协同工作?Retrofit 的核心优势是什么?](#6. Retrofit 如何与 OkHttp 协同工作?Retrofit 的核心优势是什么?)
    • [7. Retrofit 接口方法中,@Path、@Query、@Body、@Header 等注解的作用及底层解析逻辑?](#7. Retrofit 接口方法中,@Path、@Query、@Body、@Header 等注解的作用及底层解析逻辑?)
    • [8. Retrofit 如何处理取消请求?与 OkHttp 的取消机制有何关联?](#8. Retrofit 如何处理取消请求?与 OkHttp 的取消机制有何关联?)
    • [9. Retrofit 适配 Coroutine 的原理,suspend 方法的底层处理逻辑是什么?](#9. Retrofit 适配 Coroutine 的原理,suspend 方法的底层处理逻辑是什么?)
    • [10. Retrofit 中 ServiceMethod 的构建过程,如何解析接口注解并生成请求参数?](#10. Retrofit 中 ServiceMethod 的构建过程,如何解析接口注解并生成请求参数?)
  • [三、OkHttp & Retrofit 综合(大厂高频)](#三、OkHttp & Retrofit 综合(大厂高频))
    • [1. Retrofit 为什么要依赖 OkHttp?两者的职责边界如何划分?](#1. Retrofit 为什么要依赖 OkHttp?两者的职责边界如何划分?)
    • [2. OkHttp 中响应体(ResponseBody)为什么不能重复读取?如何解决这个问题?](#2. OkHttp 中响应体(ResponseBody)为什么不能重复读取?如何解决这个问题?)
    • [3. Retrofit 接口返回的 Call<T>,如何实现请求的重试机制?](#3. Retrofit 接口返回的 Call<T>,如何实现请求的重试机制?)
    • [4. 对比 OkHttp 和 HttpURLConnection 的优势,为什么大厂安卓开发首选 OkHttp?](#4. 对比 OkHttp 和 HttpURLConnection 的优势,为什么大厂安卓开发首选 OkHttp?)
    • [5. OkHttp 中 TCP 连接的复用与 HTTP/2 的多路复用有何区别?Retrofit 对 HTTP/2 的支持如何?](#5. OkHttp 中 TCP 连接的复用与 HTTP/2 的多路复用有何区别?Retrofit 对 HTTP/2 的支持如何?)

一、OkHttp 相关(源码+设计模式+核心用法)

1. OkHttp 的核心架构是什么?核心组件(Dispatcher、Interceptor、Call、RealCall)的职责分别是什么?

完整答案

OkHttp 核心架构是"请求分发+拦截器链"模式,基于责任链模式串联各类拦截器,完成请求的发起、处理、响应及后续逻辑,核心围绕"请求(Request)-分发(Dispatcher)-拦截(Interceptor)-连接(Connection)-响应(Response)"链路 展开。
核心组件职责

  • Dispatcher请求调度器 ,负责管理异步请求的线程池(默认核心线程池+最大线程池),维护等待队列(readyAsyncCalls)、运行队列(runningAsyncCalls)、同步运行队列(runningSyncCalls),实现请求的并发控制(默认异步最大64个请求,单个主机最大5个),分发请求并回调结果。
  • Interceptor拦截器 ,核心设计,通过责任链模式串联,分为应用拦截器和网络拦截器 ,负责请求/响应的拦截、修改(如添加请求头、日志打印、缓存处理、重试),所有请求/响应都需经过拦截器链。
  • Call请求的抽象接口 ,定义了请求的核心方法(execute() 同步、enqueue() 异步、cancel()取消),是请求的顶层封装,不负责具体实现
  • RealCall :Call 接口的唯一实现类,封装了实际的请求逻辑,持有 OkHttpClient、Request、Dispatcher等实例,负责发起同步/异步请求,触发拦截器链,处理请求结果回调。

关键词记忆答案:架构:请求分发+拦截器链;Dispatcher:调度请求、管理队列/线程池;Interceptor:责任链、拦截修改请求响应;Call:请求抽象接口;RealCall:Call实现、实际请求逻辑。

2. OkHttp 的拦截器(Interceptor)机制原理,应用拦截器与网络拦截器的区别,如何自定义拦截器?

完整答案:
机制原理 :OkHttp 拦截器基于责任链设计模式 ,将多个拦截器串联成拦截器链(Interceptor.Chain),请求发起时,从第一个拦截器开始依次执行 intercept() 方法,每个拦截器处理请求后,将请求传递给下一个拦截器,直到网络拦截器发起实际网络请求;响应返回时,从最后一个拦截器开始反向传递,每个拦截器处理响应后,传递给上一个拦截器,最终返回给调用者。核心源码:RealCall 的 getResponseWithInterceptorChain() 方法,构建拦截器链并执行
两者区别

  • 应用拦截器 :作用于应用层 ,在请求发起前(未经过任何网络处理)和响应返回后(已完成所有拦截器处理)执行 ;不关心网络请求的细节(如重定向、重试);每次请求/响应只执行一次;可获取原始请求和最终响应 。应用场景:添加公共 Header、日志记录、统一参数
  • 网络拦截器 :作用于网络层 ,在应用拦截器之后、实际网络请求之前执行 ;会跟随重定向、重试执行多次 ;能获取经过其他拦截器处理后的请求,以及网络返回的原始响应(未经过后续拦截器处理);可获取请求的连接信息。应用场景:调试网络请求、查看重定向过程、分析网络层响应

自定义拦截器

实现 Interceptor 接口,重写 intercept(Chain chain) 方法,在方法中通过 chain.request() 获取请求,修改后通过 chain.proceed(request) 传递给下一个拦截器,获取响应后修改并返回。最后通过 **OkHttpClient.Builder.addInterceptor()(应用拦截器)或 addNetworkInterceptor()(网络拦截器)**添加到 OkHttpClient 中。

关键词记忆答案:原理:责任链模式,拦截器链依次执行、反向返回;区别:应用拦截器(应用层、一次、原始请求/最终响应),网络拦截器(网络层、多次、重定向相关、原始响应);自定义:实现Interceptor,重写intercept,添加到OkHttpClient。

3. OkHttp 中 Dispatcher 的工作原理,如何实现请求的并发控制、异步请求的分发与回调?

完整答案:

  • 工作原理 :Dispatcher 是 OkHttp 的请求调度核心,内部维护3个队列 (readyAsyncCalls:等待的异步请求队列、runningAsyncCalls:运行中的异步请求队列、runningSyncCalls:运行中的同步请求队列)和1个线程池(默认是核心线程数0、最大线程数64、空闲线程存活时间60s的缓存线程池),负责接收Call 的请求,根据并发规则调度请求执行,以及回调请求结果
  • 并发控制 :通过两个核心参数控制(默认值可通过 OkHttpClient 配置):① 最大并发请求数 (maxRequests):默认64,即 runningAsyncCalls 队列中最多有64个请求同时运行;②单个主机最大并发数(maxRequestsPerHost):默认5,即同一主机(如同一域名)的请求,最多有5个同时运行。当异步请求发起时,若当前运行的异步请求数未达maxRequests,且当前主机的请求数未达 maxRequestsPerHost,则直接加入 runningAsyncCalls队列,由线程池执行;否则加入 readyAsyncCalls 队列等待,当有请求完成时,再从等待队列中取出请求执行。
  • 异步请求分发与回调 :当调用 RealCall.enqueue(Callback) 时,Dispatcher 会将请求封装为 AsyncCall(Runnable 子类),先判断是否能立即执行,能则提交到线程池执行,不能则加入等待队列;AsyncCall执行时,会调用 RealCall 的 getResponseWithInterceptorChain() 获取响应,然后通过Callback 的 onResponse() 或 onFailure() 回调结果,回调时会通过 Looper
    判断当前线程是否为主线程,若不是则切换到主线程(通过 OkHttpClient 配置CallbackExecutor,默认是主线程 Handler)

关键词记忆答案:原理:3个队列(等待/运行异步、运行同步)+1个线程池;并发控制:maxRequests(64)、maxRequestsPerHost(5),控制队列切换;异步分发:封装AsyncCall,线程池执行;回调:获取响应后,通过CallbackExecutor切换主线程回调。

4. OkHttp 的连接池(ConnectionPool)实现原理,连接复用、空闲连接回收的机制是什么?

完整答案:

  1. 实现原理 :ConnectionPool 是 OkHttp 用于管理 HTTP/TCP 连接复用的核心组件,目的是减少 频繁建立/关闭 TCP 连接的开销 (三次握手、四次挥手),提升请求效率内部维护一个双端队列,存储当前可用的连接,同时通过一个后台线程(线程名:OkHttp ConnectionPool)定期回收空闲连接。
  2. 连接复用机制 :当发起新请求时,OkHttp 会先通过 Address(包含主机、端口、协议、SSL 等信息)匹配 ConnectionPool 中是否有可用的空闲连接(RealConnection),若有则直接复用该连接发起请求,无需重新建立 TCP 连接;若没有则新建 RealConnection,发起请求后,将连接放入 ConnectionPool 中缓存,供后续相同 Address 的请求复用。复用的核心前提:两个请求的 Address 完全一致(确保连接可复用)
  3. 空闲连接回收机制 :ConnectionPool 有两个核心参数控制回收(可配置):① 空闲连接最大存活时间 (keepAliveDuration):默认5分钟,即连接空闲超过5分钟则会被回收;② 最大空闲连接数(maxIdleConnections):默认5个,即 ConnectionPool 中最多保留5个空闲连接,超过则优先回收最早空闲的连接。后台线程会每隔1秒(默认)检查队列,对满足回收条件(空闲时间超期、空闲连接数超标)的连接进行关闭,释放资源。

关键词记忆答案:原理:双端队列存RealConnection,后台线程回收;复用:按Address匹配空闲连接,复用减少TCP开销;回收:maxIdleConnections(5)、keepAliveDuration(5分钟),后台线程定期检查回收。

5. OkHttp 如何处理 HTTP 缓存?缓存策略(CacheStrategy)的核心逻辑,缓存过期、缓存失效的判断规则?

完整答案:

  1. 缓存处理流程 :OkHttp 通过 Cache 类(实现 Interceptor)实现 HTTP 缓存,缓存的核心是"请求URL+请求头"作为缓存键 ,缓存值为响应体及响应头,缓存文件存储在本地磁盘(默认目录)。当发起请求时,CacheInterceptor 会先检查本地缓存,根据缓存策略判断是否可用,若可用则直接返回缓存响应;若不可用则发起网络请求,请求成功后,将响应缓存到本地,再返回响应
  2. CacheStrategy 核心逻辑 :核心是"判断本地缓存是否可用,是否需要发起网络请求 ",通过对比请求头(如 Cache-Control、If-Modified-Since)和缓存的响应头,生成三种策略:① 直接使用缓存(不用发网络请求);② 发起网络请求(缓存不可用);③ 发起条件请求(如带 If-Modified-Since,验证缓存是否更新,若未更新则使用缓存)。核心源码:CacheStrategy.Factory 类,通过计算请求和缓存响应的相关参数,生成最终策略。
  3. 缓存过期判断 :主要依据响应头中的 Cache-Control 和 Expires 字段:① Cache-Control: max-age=xxx(单位秒):从响应生成时间开始,超过 xxx 秒则缓存过期;② Expires:指定缓存过期的具体时间,若当前时间超过该时间则过期;③ 若两者都存在,优先使用 max-age(HTTP/1.1 优先级高于 HTTP/1.0);④ 若都不存在,OkHttp 会根据响应码(如 200、304)和默认规则判断,一般不缓存或短期缓存。
  4. 缓存失效判断:除过期外,以下情况缓存失效:① 请求头中带有 Cache-Control: no-cache(需验证缓存有效性)、no-store(禁止缓存);② 响应头中带有 Cache-Control: no-store;③ 请求方法为 POST、PUT、DELETE 等(默认不缓存,除非有特殊配置);④ 缓存的响应码不支持缓存(如 404、500 等错误响应);⑤ 条件请求返回 200(表示缓存已更新),原缓存失效。

关键词记忆答案:缓存处理:Cache拦截器,URL+请求头为键,本地磁盘存储;CacheStrategy:判断缓存可用/需网络/条件请求;过期:max-age(优先)、Expires;失效:no-cache/no-store、非GET请求、错误响应、缓存更新。

6. OkHttp 中用到了哪些设计模式?(至少列举3种,结合源码场景说明)

完整答案:

  1. 建造者模式核心应用于 OkHttpClient、Request、Response 的构建。例如 OkHttpClient.Builder,通过链式调用设置拦截器、连接池、超时时间等参数,最终调用 build() 方法生成 OkHttpClient 实例;Request.Builder 用于构建请求,设置 URL、请求方法、请求头、请求体等,避免多参数构造器的繁琐,提升代码可读性和扩展性。
  2. 责任链模式核心应用于拦截器链。所有 Interceptor 串联成 Interceptor.Chain,请求依次经过每个拦截器处理,响应反向传递,每个拦截器只负责自己的逻辑(如日志、缓存、网络请求),互不干扰,且可灵活添加/移除拦截器,符合开闭原则。源码核心:RealCall.getResponseWithInterceptorChain() 构建链并执行。
  3. 工厂模式 :应用于 Call 的创建,OkHttpClient 的 newCall(Request) 方法,通过工厂模式创建 RealCall 实例(Call 是抽象接口,RealCall 是具体实现),隐藏实例创建细节,降低耦合。此外,ConnectionPool 中创建 RealConnection 也用到简单工厂思想。
  4. 观察者模式 :应用于异步请求的回调,Call.enqueue(Callback) 中,Callback 是观察者,RealCall 是被观察者,当请求完成(成功/失败)时,被观察者通知观察者,触发 onResponse() 或 onFailure() 回调。

关键词记忆答案:1. 建造者模式:OkHttpClient、Request、Response 的 Builder 链式构建;2. 责任链模式:拦截器链,依次处理请求/响应;3. 工厂模式:OkHttpClient.newCall() 创建 RealCall 实例。

7. OkHttp 如何实现异步请求的回调切换(子线程→主线程)?与 Handler、Looper 的关联是什么?

完整答案:

  1. 回调切换原理 :OkHttp 异步请求的执行的是在子线程(线程池中的线程),而 Android 中 UI 操作(如回调中更新 UI)必须在主线程,因此需要将回调从子线程切换到主线程。核心依赖 OkHttpClient 配置的 CallbackExecutor(回调执行器),默认实现是主线程 Handler
  2. 与 Handler、Looper 的关联:OkHttpClient 默认的 CallbackExecutor,内部持有一个主线程 Handler(通过 Looper.getMainLooper() 获取主线程的 Looper,创建 Handler)。当异步请求在子线程执行完成后,获取到响应(或失败信息),会通过 CallbackExecutor 的 execute() 方法,将回调任务(Runnable)提交到主线程的消息队列中;主线程的 Looper 循环读取消息队列,执行该 Runnable,从而在主线程触发 Callback 的 onResponse() 或 onFailure() 方法,完成线程切换。

关键词记忆答案:切换原理:依赖 CallbackExecutor(默认主线程Handler);关联:Handler 持有主线程 Looper,子线程通过 Handler 发送回调任务到主线程消息队列,Looper 循环执行,完成切换。

8. OkHttp 对 HTTPS 的支持原理,SSL 证书校验的流程,如何自定义证书校验逻辑?

完整答案:

  1. HTTPS 支持原理 :OkHttp 对 HTTPS 的支持,本质是基于 Java 的 SSL/TLS 协议,通过 SSLSocketFactory(SSL 套接字工厂)创建 SSL 连接,实现数据传输的加密(对称加密)、身份认证(证书校验)。OkHttp 默认内置系统信任的根证书,可与支持 HTTPS 的服务器建立加密连接,同时支持自定义 SSL 配置(如自定义证书、忽略证书校验)
  2. SSL 证书校验流程 :① 客户端(OkHttp)发起 HTTPS 请求,服务器返回自身的 SSL 证书(包含服务器公钥、证书颁发机构 CA 等信息);② OkHttp 会通过 TrustManager(信任管理器)校验该证书的合法性:先校验证书是否过期、是否被篡改,再校验证书的颁发机构是否在客户端的信任列表中(默认是系统根 CA 列表);③ 若校验通过,客户端生成随机密钥,用服务器公钥加密后发送给服务器,双方后续用该随机密钥进行对称加密通信;④ 若校验失败,直接抛出 SSLHandshakeException,中断请求。
  3. 自定义证书校验逻辑:① 自定义 TrustManager:实现 X509TrustManager 接口,重写 checkClientTrusted、checkServerTrusted 方法,在方法中实现自定义校验规则(如只信任指定的证书,忽略系统根证书);② 创建 SSLContext:通过 SSLContext.getInstance("TLS") 获取 SSL 上下文,初始化时传入自定义的 TrustManager;③ 配置 OkHttpClient:将 SSLContext 生成的 SSLSocketFactory,以及自定义的 HostnameVerifier(可选,校验主机名)设置到 OkHttpClient.Builder 中,即可实现自定义证书校验。(注:生产环境不建议忽略证书校验,存在安全风险)

关键词记忆答案:HTTPS 支持:基于 SSL/TLS,通过 SSLSocketFactory 创建加密连接;校验流程:服务器返回证书→TrustManager 校验(过期、篡改、CA 信任)→校验通过则加密通信;自定义:实现 X509TrustManager,创建 SSLContext,配置到 OkHttpClient。

9. RealCall 的 execute() 和 enqueue() 方法区别,底层执行流程有何不同?

完整答案:

RealCall 是 Call 接口的唯一实现,execute() 和 enqueue() 分别对应同步请求和异步请求,核心区别的是执行线程、阻塞性及回调方式,底层执行流程核心差异在"线程调度"和"结果返回方式"。

  1. 方法区别
  • execute():同步请求方法,调用后会阻塞当前线程,直到请求完成(返回 Response)或抛出异常;只能在非主线程调用(Android 中主线程调用会抛出 NetworkOnMainThreadException);无回调,直接返回结果。
  • enqueue(Callback):异步请求方法,调用后不会阻塞当前线程,直接返回,请求在子线程(Dispatcher 的线程池)中执行;执行完成后,通过 Callback 的 onResponse()/onFailure() 回调结果(默认切换到主线程);可在主线程直接调用。
  1. 底层执行流程差异:
  • execute() 流程:① 调用 RealCall.execute(),先检查请求是否已被执行(避免重复执行);② 调用 Dispatcher 的 executed(this) 方法,将当前 Call 加入 runningSyncCalls 队列;③ 调用 getResponseWithInterceptorChain() 执行拦截器链,发起网络请求,获取响应;④ 请求完成后,调用 Dispatcher 的 finished(this) 方法,从 runningSyncCalls 队列中移除;⑤ 直接返回 Response 或抛出异常。
  • enqueue() 流程:① 调用 RealCall.enqueue(Callback),检查请求是否已被执行;② 调用 Dispatcher 的 enqueue(new AsyncCall(callback)) 方法;③ Dispatcher 判断当前请求是否能立即执行(未达并发上限),能则提交到线程池执行 AsyncCall,不能则加入 readyAsyncCalls 队列;④ AsyncCall 执行时,调用 getResponseWithInterceptorChain() 获取响应;⑤ 调用 CallbackExecutor 切换到主线程,触发 Callback 回调;⑥ 回调完成后,调用 Dispatcher 的 finished(this) 方法,从 runningAsyncCalls 队列移除,并从等待队列中取出下一个请求执行。

关键词记忆答案:区别:execute() 同步、阻塞当前线程、无回调;enqueue() 异步、不阻塞、Callback 回调;流程差异:execute() 直接执行拦截器链、返回结果;enqueue() 封装 AsyncCall、线程池执行、回调切换线程。

二、Retrofit 相关(源码+设计模式+核心用法)

1. Retrofit 的核心工作流程,从接口定义到发起网络请求的完整链路是什么?

完整答案

Retrofit 核心是"接口代理+请求适配",本质是对 OkHttp 的封装,简化网络请求代码,核心工作流程分为5步,完整链路如下:

  1. 定义接口:开发者定义一个接口(如 ApiService),在接口方法上添加 HTTP 注解(如 @GET、@POST),指定请求 URL、请求参数、响应类型等(如 @GET("/api/user") Call getUser())。
  2. 创建 Retrofit 实例:通过 Retrofit.Builder 配置 baseUrl(基础URL)、addConverterFactory(响应/请求转换器,如 GsonConverterFactory)、addCallAdapterFactory(Call 适配器,如 RxJavaCallAdapterFactory)、client(关联 OkHttpClient),调用 build() 生成 Retrofit 实例。
  3. 生成接口代理对象:调用 Retrofit.create(ApiService.class),通过动态代理模式,生成 ApiService 接口的代理对象(Proxy 实例),代理对象会拦截接口方法的调用。
  4. 解析接口方法,生成请求:当调用代理对象的接口方法(如 getUser())时,动态代理会拦截该调用,解析接口方法上的注解(如 @GET、URL 路径)、方法参数(如 @Query),生成 ServiceMethod 对象(封装请求的所有信息:请求方法、URL、参数、响应类型等);ServiceMethod 结合 OkHttpClient,生成 OkHttp 的 Call 对象(RealCall)。
  5. 发起请求并处理响应:调用 Call 的 execute()(同步)或 enqueue()(异步)发起网络请求(实际由 OkHttp 执行);请求完成后,通过 Converter 转换器将 OkHttp 返回的 ResponseBody 解析为接口方法指定的实体类(如 User),通过 CallAdapter 适配返回类型(如将 Call 转为 Observable),最终通过回调或返回值将结果返回给调用者。

关键词记忆答案:流程:定义接口→创建 Retrofit 实例→生成接口代理→解析注解生成 ServiceMethod→OkHttp 发起请求→Converter 解析响应、CallAdapter 适配返回

2. Retrofit 如何将接口方法(如 @GET、@POST)转化为实际的 HTTP 请求?动态代理的应用原理?

完整答案:

  1. 接口方法转 HTTP 请求的核心:通过"动态代理+注解解析"实现,Retrofit 不直接实现接口,而是通过动态代理拦截接口方法调用,解析注解和参数,生成对应的 HTTP 请求信息,再委托 OkHttp 发起请求
  2. 动态代理应用原理:Retrofit.create(Class service) 方法是核心,底层使用 Java 动态代理(Proxy.newProxyInstance())生成接口的代理对象 ServiceMethod
  • ServiceMethod 调用 toCall(args) 方法,将方法参数转化为 HTTP 请求参数(如 @Query 参数拼接到 URL,@Body 参数转为 RequestBody),结合 Retrofit 配置的 OkHttpClient,生成 OkHttp 的 Call 对象,即实际的 HTTP 请求载体。
    关键词记忆答案:转化方式:动态代理拦截接口方法,解析注解和参数,生成 ServiceMethod,封装请求信息,委托 OkHttp 发起请求;动态代理:通过 Proxy.newProxyInstance() 生成代理对象,InvocationHandler.invoke() 解析方法、生成请求。

3. Retrofit 的 Converter 转换器原理,如何自定义 Converter(如解析自定义格式数据)

完整答案:

  1. Converter 转换器原理 :Converter 的核心作用是"数据格式转换",分为两类:① 请求转换器 ② 响应转换器
  2. Retrofit 内部通过 Converter.Factory 工厂模式管理转换器,默认无内置转换器,需手动添加(如 GsonConverterFactory、JacksonConverterFactory),添加后 Retrofit 会根据请求/响应的类型,自动匹配对应的 Converter。
  3. 核心流程:当发起请求时,ServiceMethod 会通过 Retrofit 的 converterFactories 列表,找到对应的 RequestBodyConverter,将方法参数转为 RequestBody;当请求响应时,同样通过 converterFactories 找到对应的 ResponseBodyConverter,将 ResponseBody 解析为目标实体类。
  4. 自定义 Converter :需实现 Converter 接口和 Converter.Factory 工厂类,步骤如下:
    定义自定义 Converter :实现 Converter<F, T> 接口,F 是转换前类型(如 Request 时的实体类、Response 时的 ResponseBody),T 是转换后类型(如 RequestBody、实体类),重写 convert(F value) 方法,实现具体的转换逻辑(如解析 XML、自定义 JSON 格式)。
    定义 Converter.Factory :继承 Converter.Factory,重写 requestBodyConverter()(请求转换)和 responseBodyConverter()(响应转换)方法,返回自定义的 Converter 实例,指定支持的类型(如只支持特定实体类、特定格式)
    配置 Retrofit:通过 Retrofit.Builder.addConverterFactory(new 自定义Factory()) 添加自定义转换器,优先级高于已添加的转换器(先添加的转换器优先级低,后添加的优先级高)。

关键词记忆答案:原理:分为请求/响应转换器,通过 Converter.Factory 管理,实现数据格式转换(实体→RequestBody、ResponseBody→实体);自定义:实现 Converter 和 Converter.Factory,重写转换方法,添加到 Retrofit 配置。

4. Retrofit 的 CallAdapter 适配器原理,与 OkHttp Call 的关联,如何自定义 CallAdapter(如适配 RxJava、Coroutine)

完整答案:

  1. CallAdapter 的核心作用是"适配请求返回类型",将 Retrofit 内部生成的 OkHttp Call,适配为接口方法指定的返回类型(如 Call< T>、Observable< T>、Flow< T>),解耦 OkHttp Call 与上层调用的返回类型,提升灵活性。

  2. Retrofit 内部通过 CallAdapter.Factory 工厂模式管理 CallAdapter,默认只有 CallAdapter.Factory(返回 Call),若需适配 RxJava、Coroutine,需添加对应的 CallAdapterFactory(如 RxJava3CallAdapterFactory、CoroutineCallAdapterFactory)。

  3. 核心流程:当解析接口方法时,ServiceMethod 会通过 Retrofit 的 callAdapterFactories 列表,找到能适配当前方法返回类型的 CallAdapter;请求发起后,CallAdapter 会将 OkHttp Call 包装为接口方法指定的返回类型(如将 Call 转为 Observable),并处理请求的执行、取消、回调等逻辑。

  4. 与 OkHttp Call 的关联:OkHttp Call 是 Retrofit 请求的底层载体 ,Retrofit 的 CallAdapter 不改变 OkHttp Call 的核心逻辑(发起请求、获取响应),只是对其进行"包装"和"适配",将 OkHttp 的同步/异步请求,适配为上层框架(如 RxJava、Coroutine)的调用方式(如订阅、协程挂起)。例如,RxJava 的 CallAdapter 会将 OkHttp 的 enqueue() 异步请求,转化为 Observable 的 subscribe() 订阅逻辑,回调结果通过 Observable 发射。

  5. 自定义 CallAdapter:需实现 CallAdapter 接口和 CallAdapter.Factory 工厂类,步骤如下:

    定义自定义 CallAdapter :实现 CallAdapter<T, R> 接口,T 是接口方法的返回类型(如自定义的 MyCall),R 是适配后的类型(如 OkHttp Call),重写 responseType()(返回响应数据类型)和 adapt(Call call)(将 OkHttp Call 适配为自定义返回类型)。

    定义 CallAdapter.Factory :继承 CallAdapter.Factory,重写 get() 方法,判断当前方法的返回类型是否是自定义类型,若是则返回自定义 CallAdapter 实例。

    配置 Retrofit:通过 Retrofit.Builder.addCallAdapterFactory(new 自定义Factory()) 添加自定义适配器,优先级高于已添加的适配器。

关键词记忆答案:原理:适配返回类型,通过 CallAdapter.Factory 管理,包装 OkHttp Call;与 OkHttp Call 关联:适配不改变底层请求逻辑,仅包装调用方式;自定义:实现 CallAdapter 和 CallAdapter.Factory,重写适配方法,添加到 Retrofit 配置。

5. Retrofit 中用到了哪些设计模式?(结合源码,重点说明动态代理、工厂模式、适配器模式)

  1. 动态代理模式 (核心):应用于接口代理对象的生成,对应 Retrofit.create(Class service) 方法。源码中,通过 Proxy.newProxyInstance() 生成接口的代理对象,InvocationHandler 拦截接口方法调用,解析注解和参数,生成 ServiceMethod 和 OkHttp Call,实现"接口无实现类却能发起请求"的效果,隐藏底层请求逻辑,降低耦合。
  2. 工厂模式 :核心应用于 Converter 和 CallAdapter 的创建,对应 Converter.Factory 和 CallAdapter.Factory。例如,GsonConverterFactory 是 Converter 的工厂类,通过 create() 方法生成 GsonRequestBodyConverter 和 GsonResponseBodyConverter;CallAdapter.Factory 用于生成不同类型的 CallAdapter(如默认的 CallAdapter、RxJava 的 CallAdapter)。工厂模式隐藏了转换器、适配器的创建细节,可灵活扩展(如添加自定义 Converter/CallAdapter),符合开闭原则。
  3. 适配器模式 :核心应用于 CallAdapter,对应 CallAdapter 接口。OkHttp 的 Call 是底层请求载体,而 Retrofit 接口方法的返回类型可能是 Call、Observable、Flow 等,CallAdapter 作为适配器,将 OkHttp Call 适配为不同的返回类型,使上层调用无需关心底层 OkHttp 的实现,实现"同一请求逻辑,多种返回类型"的适配,解决 OkHttp Call 与上层返回类型的兼容性问题。
  4. 建造者模式 ,应用于 Retrofit.Builder,通过链式调用配置 baseUrl、Converter、CallAdapter 等参数,生成 Retrofit 实例,简化实例创建流程。

关键词记忆答案:1. 动态代理:Retrofit.create() 生成接口代理,拦截方法、解析注解;2. 工厂模式:Converter.Factory、CallAdapter.Factory,创建转换器/适配器;3. 适配器模式:CallAdapter,适配 OkHttp Call 为不同返回类型。

6. Retrofit 如何与 OkHttp 协同工作?Retrofit 的核心优势是什么?

完整答案:

  1. 协同工作原理:Retrofit 本质是 OkHttp 的"封装器",自身不负责实际的网络请求,所有网络请求都委托给 OkHttp 执行,两者职责分工明确,协同流程如下:
  • 配置关联:Retrofit 创建时,通过 Retrofit.Builder.client(OkHttpClient) 关联 OkHttp 客户端(若不配置,Retrofit 会自动创建默认的 OkHttpClient 实例),后续所有请求都通过该 OkHttpClient 发起。
  • 请求生成 :Retrofit 通过动态代理解析接口注解和参数 ,生成 ServiceMethod(封装请求信息),再通过 ServiceMethod.toCall() 方法,调用 OkHttpClient.newCall(Request),生成 OkHttp 的 RealCall(实际请求载体)。
  • 请求执行 :Retrofit 的 Call(如 Retrofit 的 Call 接口,底层是 OkHttp RealCall)的 execute()、enqueue() 方法,本质是调用 OkHttp RealCall 的对应方法,发起网络请求。
  • 响应处理:OkHttp 执行请求后返回 Response,Retrofit 接收该 Response,通过 Converter 转换器解析响应体,通过 CallAdapter 适配返回类型,最终将结果返回给调用者。
  1. Retrofit 核心优势
  • 解耦性强:通过接口+注解的方式定义请求,将请求参数、URL、响应类型与请求逻辑分离,代码简洁、可读性高,便于维护和测试。
  • 扩展性强:支持自定义 Converter(适配不同数据格式)、CallAdapter(适配不同返回类型,如 RxJava、Coroutine),可灵活扩展功能。
  • 简化开发:封装了 OkHttp 的繁琐配置(如拦截器、连接池),开发者只需关注接口定义和业务逻辑,无需编写 OkHttp 的重复代码。
  • 类型安全:通过泛型指定响应类型,编译期即可检查类型错误,避免运行时类型转换异常(相比 OkHttp 手动解析 ResponseBody 更安全)。

关键词记忆答案:协同工作:Retrofit 封装请求(解析注解、生成请求),委托 OkHttp 执行实际网络请求,接收响应后解析适配;核心优势:解耦、可扩展、简化开发、类型安全。

7. Retrofit 接口方法中,@Path、@Query、@Body、@Header 等注解的作用及底层解析逻辑?

完整答案

  1. 各注解作用及底层解析逻辑
  • @Path:作用:用于替换 URL 路径中的占位符(如 @GET("/api/user/{id}")),参数需与占位符名称一致;解析逻辑:Retrofit 解析 @Path 注解时,会获取注解的 value(占位符名称)和方法参数值,将占位符替换为参数值,拼接成完整的请求 URL,注意参数需为基本类型或 String,避免特殊字符(需手动编码)
  • @Query:作用:用于添加 URL 查询参数(如 @GET("/api/user") Call getUser(@Query("name") String name)),最终拼接为 URL?name=xxx;解析逻辑:解析 @Query 注解的 value(参数名)和方法参数值,将参数名和值拼接为 key=value,添加到 URL 的查询字符串中,若参数为 null,该查询参数会被忽略;可通过 @QueryMap 批量添加多个查询参数
  • @Body:作用:用于设置 HTTP 请求体(如 POST 请求的 JSON 数据),参数通常是实体类;解析逻辑:Retrofit 会通过配置的 RequestBodyConverter,将实体类参数转化为 OkHttp 的 RequestBody(如通过 Gson 转为 JSON 字符串),同时设置请求头 Content-Type(如 application/json),仅支持 POST、PUT 等可带请求体的方法
  • @Header:作用:用于设置单个请求头(如 @Header("Token") String token);解析逻辑:解析 @Header 注解的 value(请求头名称)和方法参数值,将请求头添加到请求中,若参数为 null,该请求头会被忽略;若需添加固定请求头(参数不变),可使用 @Headers 注解(如 @Headers("Content-Type: application/json")),解析时直接添加到请求头,无需方法参数。
  1. 解析核心所有注解的解析都在 ServiceMethod 的构建过程中完成,通过 ParameterHandler 处理每个方法参数,根据注解类型,将参数转化为请求的 URL 部分、请求头、请求体,最终生成 OkHttp 的 Request 对象。

关键词记忆答案:@Path:替换 URL 占位符,解析后拼接 URL;@Query:添加 URL 查询参数;@Body:设置请求体,通过 Converter 转 RequestBody;@Header:设置单个请求头;解析:ServiceMethod 中通过 ParameterHandler 处理,转化为请求对应部分。

8. Retrofit 如何处理取消请求?与 OkHttp 的取消机制有何关联?

完整答案:

  1. Retrofit 取消请求的方式 :Retrofit 的取消请求完全依赖 OkHttp 的取消机制,核心通过 Call 接口的 cancel() 方法实现,具体分为两种场景:
  • 同步请求 (execute()):调用 Call.cancel() 方法,会中断当前正在执行的请求,抛出 IOException(Canceled),终止请求流程
  • 异步请求 (enqueue()):调用 Call.cancel() 方法,会取消正在执行的请求 (若请求已在运行),或从 Dispatcher 的队列中移除(若请求还在等待),同时 Callback 不会被调用(或仅调用 onFailure(),具体取决于取消时机)
  • 补充:若使用 RxJava、Coroutine 适配,可通过其自身的取消机制(如 Disposable.dispose()、CoroutineScope.cancel())间接调用 Retrofit Call 的 cancel() 方法,实现请求取消。
  1. 与 OkHttp 取消机制的关联 :Retrofit 的 Call 接口底层封装的是 OkHttp 的 RealCall,因此 Retrofit 的 cancel() 方法,本质是调用 OkHttp RealCall 的 cancel() 方法,两者取消机制完全一致,Retrofit 未新增额外的取消逻辑,仅做了一层封装
  • OkHttp 取消机制核心 :RealCall 内部持有一个 volatile boolean canceled 标志,调用 cancel() 时会将该标志设为 true;同时,若请求已发起(如已建立 TCP 连接),会关闭底层的 InputStream/OutputStream,中断网络请求;Dispatcher 会定期检查队列中的请求,若发现 canceled 为 true,会移除该请求,不再执行。
  1. 注意事项:取消请求后,Call 对象不可再次使用(再次调用 execute()/enqueue() 会抛出异常),需重新创建 Call 对象。
    关键词记忆答案:Retrofit 取消:调用 Call.cancel(),依赖 OkHttp 机制;关联:Retrofit Call 封装 OkHttp RealCall,cancel() 本质调用 RealCall.cancel();OkHttp 核心:canceled 标志+关闭流+Dispatcher 移除请求。

9. Retrofit 适配 Coroutine 的原理,suspend 方法的底层处理逻辑是什么?

完整答案:

  1. 适配 Coroutine 的原理:Retrofit 对 Coroutine 的适配,核心是通过 **CoroutineCallAdapterFactory(**需添加 retrofit2:adapter-coroutines 依赖),将 Retrofit 的 Call 适配为协程的挂起函数(suspend 方法),实现异步请求的协程化调用,无需手动处理 Call 的 enqueue() 回调,简化异步代码。
  • 核心逻辑:CoroutineCallAdapterFactory 会生成 CoroutineCallAdapter,该适配器会将 OkHttp 的 Call 包装为协程的挂起函数,通过协程的调度器(如 Dispatchers.IO)执行网络请求,请求完成后将结果返回,实现"同步代码写法,异步执行"
  1. suspend 方法的底层处理逻辑 :Retrofit 支持接口方法添加 suspend 关键字(如 @GET("/api/user") suspend fun getUser(): User),底层处理分为3步:
    接口解析 :Retrofit 解析接口方法时,若方法带有 suspend 关键字,会将方法的返回类型(如 User)包装为 Call<Response< T>>(底层还是 OkHttp Call),同时识别该方法为协程挂起方法
    挂起执行 :当调用 suspend 方法时,CoroutineCallAdapter 会将 OkHttp 的异步请求(enqueue())封装为协程的挂起函数 ,通过 withContext(Dispatchers.IO) 将请求切换到 IO 子线程执行,避免阻塞主线程
    结果返回:请求执行完成后,若成功,通过 Converter 解析 ResponseBody 为目标实体类(如 User),直接返回;若失败,抛出异常(需在协程中通过 try-catch 捕获),无需通过 Callback 回调
  • 源码细节:Retrofit 对 suspend 方法的支持,依赖 Kotlin 的协程机制,底层通过 Continuation(续体)实现挂起和恢复,当请求完成后,通过 Continuation.resume() 恢复协程,返回结果。

关键词记忆答案:适配原理:通过 CoroutineCallAdapterFactory,将 Call 适配为协程挂起函数;suspend 处理:解析为挂起方法,IO 子线程执行 OkHttp 请求,请求完成后解析结果并恢复协程、返回数据。

10. Retrofit 中 ServiceMethod 的构建过程,如何解析接口注解并生成请求参数?

完整答案:

  1. ServiceMethod 构建过程 :ServiceMethod 是 Retrofit 解析接口方法的核心类,封装了请求的所有信息(请求方法、URL、参数、响应类型、Converter、CallAdapter 等),其构建过程在 Retrofit.create() 生成代理对象后,首次调用接口方法时触发(Retrofit 会缓存 ServiceMethod,避免重复构建),具体过程:
    初始化 :通过 ServiceMethod.Builder 初始化,传入 Retrofit 实例、被调用的 Method(接口方法),获取方法上的所有注解(HTTP 注解、Headers 注解等)
    解析 HTTP 注解 :解析方法上的 HTTP 注解(如 @GET、@POST),获取请求方法(GET/POST)、URL 路径(相对路径,结合 Retrofit 的 baseUrl 生成完整 URL),处理 URL 中的占位符(如 {id})
    解析方法参数 :遍历方法的所有参数,解析每个参数上的注解(如 @Path、@Query、@Body、@Header),创建对应的 ParameterHandler(参数处理器),用于后续将参数转化为请求的对应部分(URL 占位符、查询参数、请求体、请求头)
    配置 Converter 和 CallAdapter :根据方法的返回类型,从 Retrofit 的 converterFactories 中获取对应的 ResponseBodyConverter(响应解析)和 RequestBodyConverter(请求转换);从 callAdapterFactories 中获取对应的 CallAdapter(返回类型适配)
    构建 ServiceMethod:调用 ServiceMethod.Builder.build(),生成 ServiceMethod 实例,缓存到 Retrofit 的 serviceMethodCache 中,供后续相同方法调用时复用
  2. 注解解析与请求参数生成 :核心由 ParameterHandler 完成,不同注解对应不同的 ParameterHandler
  3. 最终,ServiceMethod 通过 toCall(args) 方法,调用所有 ParameterHandler 处理方法参数,结合解析到的请求信息,生成 OkHttp 的 Request 对象,进而生成 Call 实例。

关键词记忆答案:ServiceMethod 构建:初始化→解析 HTTP 注解→解析方法参数→配置 Converter/CallAdapter→构建缓存;注解解析:通过 ParameterHandler 处理不同注解,将参数转化为 URL、请求体、请求头,生成 OkHttp Request。

三、OkHttp & Retrofit 综合(大厂高频)

1. Retrofit 为什么要依赖 OkHttp?两者的职责边界如何划分?

完整答案:

  1. Retrofit 依赖 OkHttp 的核心原因 :Retrofit 的定位是"网络请求封装框架",核心目标是简化接口定义和请求调用,自身不具备发起网络请求 、处理 TCP 连接、拦截器、连接池、缓存等底层网络能力;而 OkHttp 是成熟的底层网络请求框架,具备上述所有底层能力,且性能优异、扩展性强,Retrofit 依赖 OkHttp 可避免重复开发底层网络逻辑,专注于上层接口封装和数据解析,提升开发效率和稳定性
  2. 两者职责边界
  • OkHttp 职责 (底层网络层):负责实际的网络请求执行,包括:建立/复用 TCP 连接(ConnectionPool)、发起 HTTP/HTTPS 请求、处理拦截器(请求/响应拦截)、缓存管理、并发控制(Dispatcher)、SSL 证书校验、请求取消等底层网络操作,核心是"发起请求、获取响应"。
  • Retrofit 职责 (上层封装层):负责接口定义和请求适配,包括:通过接口+注解定义请求、动态代理解析注解和参数、生成请求信息(ServiceMethod)、通过 Converter 实现数据格式转换(实体→RequestBody、ResponseBody→实体)、通过 CallAdapter 适配返回类型(Call→Observable/Flow)、将请求委托给 OkHttp 执行,核心是"简化请求调用、解析响应数据"。
  1. 总结:OkHttp 是"执行者",负责底层网络通信;Retrofit 是"组织者",负责上层接口封装和数据处理,两者协同实现高效、简洁的网络请求

关键词记忆答案:依赖原因:Retrofit 无底层网络能力,OkHttp 具备成熟底层网络能力,避免重复开发;职责边界:OkHttp(底层,发起请求、处理网络细节),Retrofit(上层,接口封装、数据解析、请求适配)。

2. OkHttp 中响应体(ResponseBody)为什么不能重复读取?如何解决这个问题?

完整答案:

  1. 不能重复读取的核心原因 (底层设计)
    OkHttp 的 ResponseBody 底层是基于流(InputStream)实现的,流的特性是"一次性读取"------读取后指针会移动到流的末尾,没有重置(reset)机制,且 ResponseBody 内部没有缓存流的数据;同时,OkHttp 为了节省内存,采用"懒加载"机制,响应体的数据不会一次性加载到内存中,而是在调用 string()、byteStream() 等方法时才开始读取,读取完成后流会被关闭,因此无法重复读取
  2. 解决方法
    方案1:读取后缓存数据
    方案2:使用 ResponseBody 的 clone() 方法(推荐,OkHttp 自带)
    方案3:自定义 ResponseBody,重写流的读取逻辑

关键词记忆答案:原因:ResponseBody 基于流实现,流一次性读取、无重置,懒加载且读取后关闭;解决:缓存读取结果、clone() 复制实例、自定义 ResponseBody 缓存流数据。

3. Retrofit 接口返回的 Call,如何实现请求的重试机制?

完整答案:

Retrofit 的 Call 本身不具备重试能力,需基于 OkHttp 或 Retrofit 自身扩展实现,核心有3种常用方案,均不侵入接口定义,可全局或局部配置:
方案1:基于 OkHttp 重试拦截器(全局生效,推荐)
自定义重试拦截器 :实现 Interceptor,重写 intercept 方法,捕获可重试的异常(如网络超时、连接失败、500/502 服务器错误),设置重试次数(如3次)、重试间隔(如1s)
逻辑 :在拦截器中循环调用 chain.proceed(request),每次失败后判断是否达到最大重试次数、是否属于可重试场景,若满足则延迟后重试,否则抛出异常
方案2:自定义 Call 包装类(局部生效,灵活)
方案3:基于 Retrofit CallAdapter(全局生效,结合响应码重试)

关键词记忆答案:核心:基于 OkHttp 拦截器(全局)、Call 包装类(局部)、CallAdapter(结合响应码);逻辑:捕获可重试异常/响应码,设置次数/间隔,循环调用请求方法。

4. 对比 OkHttp 和 HttpURLConnection 的优势,为什么大厂安卓开发首选 OkHttp?

HttpURLConnection 是 Android 原生内置的网络请求工具,接口简单但功能简陋、性能一般
关键词记忆答案:OkHttp 优势:性能优(连接复用、HTTP/2)、功能全(拦截器、HTTPS、缓存)、容错强、易用、可扩展;大厂首选:性能稳定、开发高效、扩展性强、社区成熟,适配复杂业务和海量用户。

5. OkHttp 中 TCP 连接的复用与 HTTP/2 的多路复用有何区别?Retrofit 对 HTTP/2 的支持如何?

TCP 连接复用是"多个连接共用一个 TCP 通道 ",而 HTTP/2 多路复用是"一个 TCP 通道中同时传输多个请求 ",两者可叠加使用(如 OkHttp 复用 TCP 连接,同时在该连接中通过 HTTP/2 多路复用传输多个请求),进一步提升性能。
关键词记忆答案:区别:TCP 连接复用(TCP 层面,复用连接减开销),HTTP/2 多路复用(请求层面,同一连接多请求,解队头阻塞);Retrofit 支持:依赖 OkHttp 自动支持,无需额外配置,服务器支持则启用,不支持自动降级。

相关推荐
恋猫de小郭2 小时前
抖音“极客”适配 Android 5 ~ 9 等老机型技术解读,都是骚操作
android·前端·flutter
黄林晴2 小时前
Android Studio Panda 4 来了!AGP 9.2 升级,同步稳定性大幅修复
android·android studio
默 语2 小时前
OpenClaw“养龙虾“热潮降温的深层解析:从技术狂欢到理性回归
android·开发语言·kotlin
xiaoshiquan12062 小时前
Android16系统内容全屏,状态栏和导航栏透明
android
白眼黑刺猬2 小时前
如何构建 Flink SQL 任务的血缘分析
大数据·面试·职场和发展·flink
Carson带你学Android2 小时前
编译更快、语法更香?一文看懂 Kotlin 2.3.20 的 6 大核心演进
android·kotlin
jwn9992 小时前
Laravel3.x经典特性全解析
android
苦瓜小生2 小时前
天玑学堂Agent面试总结(二)「持续更新」
面试·职场和发展
followYouself2 小时前
Android点击事件分发流程
android·事件分发机制