当前位置: 首页 > web >正文

Android Retrofit框架分析(三):自动切换回主线程;bulid的过程;create方法+ServiceMethod源码了解

目录

  1. Okhttp有什么不好?
  2. bulid的过程
  3. create方法+ServiceMethod
  4. call + enqueue的过程
  5. 为什么要学习源码呢?

一、Okhttp有什么不好?

Okhttp本身来说,是一个挺好的网络框架,但,对于开发者而言,使用起来,会过于繁琐。下面我们看看一个代码:

// 1️⃣ 手动拼接URL和参数(容易出错)
HttpUrl url = HttpUrl.parse("https://api.example.com/user").newBuilder().addQueryParameter("id", "123").build();// 2️⃣ 创建请求对象
Request request = new Request.Builder().url(url).build();// 3️⃣ 发起异步请求
OkHttpClient client = new OkHttpClient();
client.newCall(request).enqueue(new Callback() {@Overridepublic void onResponse(Call call, Response response) throws IOException {// 4️⃣ 手动解析JSON(容易遗漏判空)String json = response.body().string();User user = new Gson().fromJson(json, User.class);// 5️⃣ 手动切回主线程更新UI(忘记切换会崩溃)runOnUiThread(() -> {textView.setText(user.getName());});}@Overridepublic void onFailure(Call call, IOException e) {// 6️⃣ 手动处理失败逻辑(比如Toast错误)}
});

​问题总结​​:

  • ​代码臃肿​​:每个请求都要写重复代码(拼参数、解析JSON、线程切换)。
  • ​维护困难​​:如果接口路径或参数变更,需要全局搜索修改。
  • ​容错成本高​​:手动处理空指针、JSON解析异常、线程安全问题。

下面我们看看Retrofit的代码:

// 1️⃣ 声明接口(像写文档一样直观)
public interface ApiService {@GET("user")Call<User> getUser(@Query("id") String id); // 自动拼接参数
}// 2️⃣ 发起请求(3行代码搞定)
ApiService service = retrofit.create(ApiService.class);
service.getUser("123").enqueue(new Callback<User>() {@Overridepublic void onResponse(Call<User> call, Response<User> response) {// ✅ 自动解析JSON → User对象// ✅ 自动切回主线程textView.setText(response.body().getName());}
});

优化原理​​:

  • ​声明式API​​:用注解代替手动拼参数(如@GET定义接口路径,@Query自动拼接URL参数)。
  • ​自动解析​​:通过GsonConverter直接将JSON转成User对象。
  • ​线程安全​​:回调时自动切换回主线程(背后是MainThreadExecutor)。

那么他是如何做到的呢?接下来,我们看看源码。


二、bulid的过程

Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/")  // 必填:API根路径.client(new OkHttpClient())          // 选填:自定义OkHttp(比如加日志拦截器).addConverterFactory(GsonConverterFactory.create()) // 选填:数据解析器.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 选填:适配RxJava.build();

这个主要是做什么?可以理解为就是将所需的参数全部保存起来,方便后面使用,比如url,数据解析器等,都是为后面发起请求,和接收响应进行使用,使用bulid构建一个Retrofit,这就是bulid的作用。我们可以进入他的源码看看:

比如addConverterFactory以及addCallAdapterFactory方法,都是使用List来保存起来,

在这里插入图片描述

url也是

在这里插入图片描述

然后使用bulid构建一个Retrofit。

在这里插入图片描述

建造过程核心逻辑​​:

  1. ​校验必填参数​​:比如baseUrl不能为空。
  2. ​设置默认组件​​:如果没配置CallAdapter,默认用ExecutorCallAdapterFactory(处理主线程回调)。
  3. ​组合所有配置​​:将ConverterCallAdapter等组件打包到Retrofit对象中。

三、create方法+ServiceMethod

// 1️⃣ 声明接口(像写文档一样直观)
public interface ApiService {@GET("user")Call<User> getUser(@Query("id") String id); // 自动拼接参数
}// 2️⃣ 发起请求(3行代码搞定)
ApiService service = retrofit.create(ApiService.class);
service.getUser("123");

当我们调用retrofit.create方法的时候,我们看看内部做了什么。

在这里插入图片描述

通过 Proxy.newProxyInstance 创建接口的代理对象,那么当我们调用service.getUser(“123”)的时候,代理对象的所有方法调用都会路由到 InvocationHandler.invoke()。让所有的接口都走 invoke函数,这样就可以拦截调用函数的执行,从而将网络接口的参数配置归一化。这个invoke方法,就是典型的AOP思想,在中间切开一个口。

invoke函数是如何完成网络请求,从这个retrofit到okhttp呢?

接下来,我们看看loadServiceMethod方法

在这里插入图片描述

这个方法返回了一个ServiceMethod,这里面主要做了什么?解析方法上的 @GET@POST 等注解,解析 @Query@Path@Body 等参数注解,解析结果会被缓存到 serviceMethodCache 避免重复解析。

每个接口方法(如 getUser())首次调用时都会生成专属的 ServiceMethod,即使同一个接口中的不同方法(如 getUser()login()),也会生成不同的 ServiceMethod,然后通过 serviceMethodCache 的 ConcurrentHashMap 缓存起来,Key 为 Method 对象。


四、call + enqueue的过程

那么接口方法上的所有信息,参数都已经拿到了,也解析好了,接下来干嘛?我们继续看回源码这里,会调用invoke方法。

在这里插入图片描述
在这里插入图片描述

创建 OkHttpCall 对象,通过传递进来的参数,json解析成对应的bean,返回封装了okhttp的call
在这里插入图片描述

在这里插入图片描述

call有了以后,接下来就是调用enqueue方法

在这里插入图片描述

在得到response以后,要返回给主线程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

底层还是handler。


五、为什么要学习源码呢?

一开始的时候,在想,为什么要看源码,看了源码以后,你了解他的原理,你也可以运用他的技术,用到其他方面,比如注解的使用,动态代理的使用。

然后也能了解他的底层逻辑,后面我们写retrofit代码的时候,也会有一种恍然大悟的感觉,比如回调的这个地方,已经自动会切换到主线程。

http://www.xdnf.cn/news/4124.html

相关文章:

  • 【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
  • Windows系统修改Docker Desktop(WSL2)内存分配
  • Facebook隐私保护措施的优缺点解析
  • Java面试全栈解析:Spring Boot、Kafka与Redis实战揭秘
  • Jenkins+Newman实现接口自动化测试
  • 蓝桥杯-通电(最小生成树java)
  • Axure : 列表分页、 列表翻页
  • 第1.3讲、什么是 Attention?——从点菜说起 [特殊字符]️
  • FastJSON 使用 `Feature.OrderedField` 修复 `JSONObject` 序列化字段顺序问题
  • 用 GRPO 魔法点亮Text2SQL 的推理之路:让模型“思考”得更像人类
  • AI服务器的作用都有哪些?
  • 【工具使用-数据可视化工具】Apache Superset
  • Cursor 被封解决方案
  • 2、Kafka Replica机制与ISR、HW、LEO、AR、OSR详解
  • .NET 通过回调函数执行 Shellcode启动进程
  • 广州华锐视点邀您参与2025广交会VRAR展【5月10-12日】
  • 快速体验 .NET9 提供的 HybridCache 混合缓存
  • wrod生成pdf。[特殊字符]改背景
  • 基于Piecewise Jerk Speed Optimizer的速度规划算法(附ROS C++/Python仿真)
  • C++多态详解
  • ORCAD打印pdf
  • Docker手动重构Nginx镜像,融入Lua、Redis功能
  • 【C++】WSL常用语法
  • 先滤波再降采样 还是 先降采样再滤波
  • IL2CPP 技术深度解析
  • std::move()详解
  • n8n 使用 Merge 节点进行数据聚合
  • 系统思考:困惑源于内心假设
  • 【AI入门】Cherry入门1:Cherry Studio的安装及配置
  • suna工具调用可视化界面实现原理分析(一)