Android Retrofit 笔记

🎯 Retrofit 的核心定位:不是网络库,是"适配器"

很多人有个误区,觉得 Retrofit 是一个网络库。其实不是,它只是一个对网络请求的封装和适配 。真正的脏活累活,都是交给 OkHttp 去干的。

它的核心价值在于:把你在 Java 接口里定义的方法和注解,转换成 OkHttp 能够发起的网络请求,再把 OkHttp 返回的 Response,通过你指定的转换器(如 Gson),解析成你想要的 Java 对象。

Retrofit 的本质流程可以概括为下图:

这个流程清晰地展示了 Retrofit 的三大阶段:设计时(注解)-> 运行时(动态代理构建请求)-> 执行时(OkHttp+转换器)。下面我们来逐一深入。

🏗️ 1. 创建 Retrofit 实例:搭建舞台

第一步就是通过 Builder 建造者模式创建 Retrofit 对象。

java 复制代码
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create()) // 数据解析器
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 返回值适配器
        .client(okHttpClient) // 可配置自定义的 OkHttpClient
        .build();

这一步的核心是把开发者的配置"固化"下来,形成一个可以生产网络请求的工厂。它内部维护了几个关键成员:

  • baseUrl:基础地址。
  • converterFactories:数据转换器工厂列表。默认内置了内置的 BuiltInConverters(处理 ResponseBodyVoid 等),我们添加的 GsonConverterFactory 就在它前面。
  • adapterFactories:返回值类型适配器工厂列表。默认会添加一个 ExecutorCallAdapterFactory,用于将 OkHttpCall 适配成能在主线程回调的 Call
  • callFactory:实际发起网络请求的工厂,默认是 OkHttpClient
  • callbackExecutor:回调执行器,在 Android 上默认是 MainThreadExecutor,通过 Handler 将回调切到主线程。

📝 2. 定义接口:编写剧本

这是 Retrofit 最迷人的地方。我们只需要定义一个 Java 接口,通过注解来"声明"一个网络请求。

java 复制代码
public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}

这里的 @GET@Path 注解就像是剧本的台词,描述了请求的所有要素。我们只关心"做什么",而不关心"怎么做"。

🎭 3. 动态代理:核心戏法

当我们调用 retrofit.create(GitHubService.class) 时,神奇的事情发生了。它并没有返回一个我们写的实现类,而是通过 JDK 动态代理 在运行时生成了一个 GitHubService 的代理对象。

关键代码在 Retrofit#create 方法中:

java 复制代码
public <T> T create(final Class<T> service) {
    // ...
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
                private final Platform platform = Platform.get();

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 如果是 Object 的方法(如 equals、hashCode),直接调用
                    if (method.getDeclaringClass() == Object.class) {
                        return method.invoke(this, args);
                    }
                    // 如果是接口的默认方法(Java 8),特殊处理
                    if (platform.isDefaultMethod(method)) {
                        return platform.invokeDefaultMethod(method, service, proxy, args);
                    }
                    // 核心逻辑:加载/创建 ServiceMethod,并调用 adapt
                    ServiceMethod<Object, Object> serviceMethod =
                            (ServiceMethod<Object, Object>) loadServiceMethod(method);
                    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            });
}

这个 InvocationHandler 就是总导演。当我们调用 gitHubService.listRepos("square") 时,实际上执行的是这里的 invoke 方法。

⚙️ 4. 从注解到请求:ServiceMethod 和 OkHttpCall

loadServiceMethod(method) 会解析我们定义的 listRepos 方法。它采用了缓存机制,同一个方法只解析一次。

解析过程由 ServiceMethod.Builder 完成,主要包括:

  1. 解析方法注解 :读取 @GET@POST@Headers 等,确定请求方式、相对路径、是否有表单等。
  2. 解析参数注解 :遍历方法的每一个参数,根据 @Path@Query@Body 等注解,创建对应的 ParameterHandler<?>。比如,@Path("user") String user 会生成一个 ParameterHandler.Path,它知道如何将 user 这个值替换到 URL 的占位符中。
  3. 确定 CallAdapter 和 Converter
    • 根据方法返回值类型(如 Call<List<Repo>>),从 adapterFactories 中找到一个能处理该类型的 CallAdapter
    • 根据 CallAdapter 解析出的响应类型(List<Repo>),从 converterFactories 中找到一个能将 ResponseBody 转换成 List<Repo>Converter
  4. 构建 RequestFactory :将所有解析出的信息(URL、Headers、ParameterHandlers 等)封装成一个 RequestFactory,它的职责就是根据传入的参数(args)最终构建出一个 okhttp3.Request

解析完成后,我们就得到了一个 ServiceMethod 对象。它持有 CallAdapterResponseConverterRequestFactory。接着,我们用它和传入的参数(args)创建一个 OkHttpCallOkHttpCall 是 Retrofit 对 okhttp3.Call 的封装,负责实际执行网络请求。

最后一步,也是体现其扩展性的关键:serviceMethod.callAdapter.adapt(okHttpCall)

  • 如果我们返回值是 Call<T>,默认的 ExecutorCallAdapterFactory 会返回一个 ExecutorCallbackCall,它内部将 OkHttpCall 的异步请求结果通过 callbackExecutor(主线程 Handler)回调给用户,实现了线程切换。
  • 如果我们添加了 RxJava2CallAdapterFactory,返回值是 Observable<T>,那么它会返回一个 Observable,当 OkHttpCall 执行成功后,通过 RxJavaEmitter 发射数据。

🌐 5. 请求与解析:真正的网络交互

当我们调用 call.enqueue(callback) 时,最终会执行到 OkHttpCallenqueue 方法。它内部会调用 createRawCall(),这个方法利用 serviceMethodRequestFactory 和传入的参数,通过 ParameterHandler 逐个设置参数,最终构建出一个 okhttp3.Request,然后用 OkHttpClient 发起异步请求。

当 OkHttp 返回 okhttp3.Response 后,OkHttpCall 会调用 parseResponse 方法。如果响应成功(code 200),它会调用 serviceMethod.toResponse(catchingBody)。这个方法里就是 responseConverter.convert(catchingBody),将网络返回的二进制数据通过我们配置的 GsonConverterFactory 解析成 List<Repo> 对象。

最终,这个解析好的对象,会通过之前 CallAdapter 设定的线程模型,回调到我们的 onResponseonNext 方法中。

💎 总结

Retrofit 的设计精髓在于将不变的部分(框架流程)和变化的部分(数据格式、调用平台)通过接口彻底解耦

  • 动态代理:优雅地拦截接口方法调用,将静态的注解转化为动态的请求描述。
  • 建造者模式 :构建复杂的 Retrofit 对象。
  • 工厂模式CallAdapter.FactoryConverter.Factory 提供了无限制的扩展能力,想支持 Protobuf?加个转换器就行。想支持 LiveData?写个适配器就行。
  • 装饰者模式ExecutorCallbackCallOkHttpCall 进行包装,增加了线程切换的功能。

所以,Retrofit 能成为事实标准,不是因为它发明了新的网络请求方式,而是因为它用最简洁、最稳定的方式,将各种优秀的库(OkHttp, Gson, RxJava)整合在了一起,让开发者能以一种近乎优雅的方式去写网络请求。

相关推荐
城东米粉儿1 小时前
Android Retrofit 线程切换 笔记
android
城东米粉儿3 小时前
Kotlin @JvmOverLoads 笔记
android
alexhilton4 小时前
把离线AI代理装进口袋里
android·kotlin·android jetpack
哈哈浩丶4 小时前
ATF (ARM Trusted Firmware) -2:完整启动流程(冷启动)
android·linux·arm开发·驱动开发
哈哈浩丶4 小时前
ATF (ARM Trusted Firmware) -3:完整启动流程(热启动)
android·linux·arm开发
哈哈浩丶4 小时前
OP-TEE-OS:综述
android·linux·驱动开发
恋猫de小郭14 小时前
你是不是觉得 R8 很讨厌,但 Android 为什么选择 R8 ?也许你对 R8 还不够了解
android·前端·flutter
城东米粉儿16 小时前
Android Glide 笔记
android
城东米粉儿16 小时前
Android TheRouter 笔记
android