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(处理 ResponseBody、Void 等),我们添加的 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 对象。它持有 CallAdapter、ResponseConverter 和 RequestFactory。接着,我们用它和传入的参数(args)创建一个 OkHttpCall。OkHttpCall 是 Retrofit 对 okhttp3.Call 的封装,负责实际执行网络请求。

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

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

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

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

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

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

💎 总结

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

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

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

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui