Android 深入Http(5)从Retrofit源码来看Http,最新Android开发面试解答

简介: Android 深入Http(5)从Retrofit源码来看Http,最新Android开发面试解答


.addConverterFactory(GsonConverterFactory.create(gson))

这样传回来的RespnseBody如果是个Json,那他就能转换成一个JavaBean。

我们就能把Api类的Call中的ResponseBody换成:

public interface GitHubService {
@GET(“users/{user}/repos”)
Call listRepos(@Path(“user”) String user);
}

这就体现了Retrofit对响应体处理的强大。

我们来读Retrofit源码结构吧。

Retrofit大致源码解析

==============================================================================

enqueue


我们以下面代码为例子:

api.getRepo().enqueue(new Callback<List>() {
@Override
public void onResponse(Call<List> call, Response<List> response) {
}
@Override
public void onFailure(Call<List> call, Throwable t) {
}
});

因为直接点进enqueue它是Call的抽象方法,而getRepo它也是个抽象方法,所以真正实现enqueue方法的应该是api对象里面的。

api又是由retrofit.create(Api.class)创建的,它创建了一个接口对象,所以我们去看create()方法,发现它终于是一个实现类了,也就是说这个方法它承接了后面所有的方法:

public T create(final Class service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(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, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

Create()是整个Retrofit的核心


这个方法它创建出了一个ApiService的实例。ApiService明明是一个接口,却能实现了其声明的所有的网络请求。

这说明这个方法是真的很顶,能把你这个接口类的所有网络请求方法整的明明白白。

我们来一行一行的分析:

第一段:

Utils.validateServiceInterface(service);

从方法名可以看出,这个方是做验证的:验证传进来的ApiService,是不是一个Interface类,我们点进去看一下:

static void validateServiceInterface(Class service) {
if (!service.isInterface()) {
throw new IllegalArgumentException(“API declarations must be interfaces.”);
}
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException(“API interfaces must not extend other interfaces.”);
}
}

是的,它首先会判断当前的类是不是一个Interface,其次它会判断当前的Interface有没有继承别的Interface,如果是的话就会抛出错误。

这个方法是做类型校验的,要求传进来的Interface类必须是原生的而且没有继承的。

第二段:

if (validateEagerly) {
eagerlyValidateMethods(service);
}

这也是一个验证,Eagerly是激进的意思,如果validateEagerly为true的话,Retrofiut会对ApiService做一个安全地、全面地验证,并且是在网络申请前做。这样的结果可能会导致程序卡一下, 而如果项目的Api很多,那我们在打开App的时候,它全都验证,那可能用户体验会极差。

所以我们一般都不会开这个玩意。

第三段

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, @Nullable Object[] args)
throws Throwable {
}
});

看到了Proxy.newProxyInstance()和里面的invoke()方法,就是动态代理咯。

也就是可以认为在Retrofit中有一个代理类,专门帮我们配置这个Api信息。

至于动态代理,说到底就是 A对象有funcation()这个方法可以去获取一些东西,可是当前情况不能直接通过A来执行funcation方法,但是B对象可以做到,那我们通过给B对象设置 funcation()方法,让B去帮我们获取这些东西。而这个代理方法的入口正是invoke()

动态代理的本质是Java的反射机制,你要弄懂动态代理,必须要先弄懂Java的反射,而我之前已经浅析过Java的反射机制,里面正好讲到了动态代理的例子,非常好理解。

链接在这里:Java反射机制

这里我讲细一点,这里有两个类,一个是代理类,一个是被代理类

  • 被代理类

newProxyInstance()中传入的第一个参数service.getClassLoader(),获取service类的ClassLoader,这就说明service是被代理类,就是我们在retrofit.create(ApiService.class)的ApiService,它无法直接去执行网络请求,所以肯定有必要找代理类去帮我包装一下做事情。

  • 代理类

代理类是newProxyInstance()的最后一个参数,在这里就是new InvocationHandler() {...},它重写了invoke()invoke()就是实际的帮被代理类 去做网络请求的 方法,实际就是它来执行 listRepos()这个方法!!!!!!

到这里,我们就知道辽,整个return 返回的是一个动态代理类,当我们调用到网络请求的时候,这个动态代理类就会调用它的invoke方法。Ok那invoke方法里面具体是做什么的呢,我们来看一下。

invoke()方法


method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}

我们看下它的参数:

  • Object proxy:代理类
  • Method method:被代理的方法,比如ApiService的 listRepos()方法
  • Object[] args:这个method的参数

了解完后我们来看下下面的内容,也分为三段:

part1:

if (method.getDeclaringClass() == Object.class) {
//如果该方法是声明方法,则直接执行这个方法
return method.invoke(this, args);
}

什么是声明方法呢?比如 MainActivity的onStart()、onResume或者toString()、onBackPressed()这种要么已经在自己类里面声明,要么在父类里面就声明的方法,则它会直接调用这个方法。

也就是说,如果我们的 网络请求 它已经被某个类给声明并且实现而不是在interface中,那么Retrofit就会直接执行它。

就是一个验证方法而已。保证我们用的方法是在interface接口中的。

part2

if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}

对不同的Java平台会做不同的行为。

所以这个也比较一般,不用去了解。

part3 重点

ServiceMethod serviceMethod =
(ServiceMethod) loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

第一行用 loadServiceMehotd()来获取一个 ServiceMethod,来看看它做了什么:

// CallAdapter.java
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method); // 获取缓存 serviceMethodCache是一个 ConcurrentHashMap结构
if (result == null) {
result = new ServiceMethod.Builder(this, method).build(); // 如果没有缓存,就用build方法生成
serviceMethodCache.put(method, result);
}
}
return result;
【附】相关架构及资料

相关文章
|
1月前
|
Linux C语言 iOS开发
C语言结合AWTK开发HTTP接口访问界面
这样,我们就实现了在C语言中使用libcurl和AWTK来访问HTTP接口并在界面上显示结果。这只是一个基础的示例,你可以根据需要添加更多的功能和优化。例如,你可以添加错误处理机制、支持更多HTTP方法(如POST、PUT等)、优化用户界面等。
76 26
|
1月前
|
人工智能 网络协议 API
开发效率翻倍!Apipost这些协议调试秘籍,从HTTP到金融报文全搞定
Apipost是一款强大的API研发管理工具,支持多种协议与数据格式,包括HTTP(s)、WebSocket、SSE、gRPC、TCP及金融协议(如ISO 8583、FIX)。它内置国密算法库,提供HTTP文件秒传、全局参数配置等实用功能。在SSE调试中,可轻松处理AI模型流式响应;WebSocket与Socket.IO实现高效实时通信;GraphQL支持可视化Query编写;TCP模块解决金融报文编码难题;gRPC则具备服务反射与流式调试能力。Apipost不仅简化了多协议切换的复杂性,还自动生成文档,显著提升开发效率,让开发者专注于核心业务逻辑。
|
1月前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
2月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
233 29
|
2月前
|
XML JSON Linux
Reqable:跨平台HTTP开发与调试工具
Reqable是一款功能强大且易于使用的跨平台HTTP开发与调试工具,具有多平台支持、全面的HTTP请求构建与解析、请求历史记录和环境管理等功能。它简化了HTTP请求的构建、发送和响应分析过程,为开发者提供了极大的便利。通过Reqable,开发者可以更高效地进行HTTP开发和调试,提高工作效率和代码质量。
209 26
|
7月前
|
Rust 前端开发 API
Tauri 开发实践 — Tauri HTTP 请求开发
本文介绍了如何在 Tauri 中发起 HTTP 请求。首先通过安装 Tauri 生态中的工具包并配置 `tauri.conf.json` 文件来允许特定域名的 HTTP 通信。接着封装了一个简单的 HTTP 客户端类,并在页面中使用该客户端实现 GET 和 POST 请求。最后提供了完整的源码地址以供参考。此功能使得桌面应用能够与远程服务器进行交互,增强了应用的实用性。
434 1
Tauri 开发实践 — Tauri HTTP 请求开发
|
2月前
|
关系型数据库 MySQL PHP
源码编译安装LAMP(HTTP服务,MYSQL ,PHP,以及bbs论坛)
通过以上步骤,你可以成功地在一台Linux服务器上从源码编译并安装LAMP环境,并配置一个BBS论坛(Discuz!)。这些步骤涵盖了从安装依赖、下载源代码、配置编译到安装完成的所有细节。每个命令的解释确保了过程的透明度,使即使是非专业人士也能够理解整个流程。
62 18
|
2月前
|
缓存 安全 数据处理
Objective-C开发:从HTTP请求到文件存储的实战
Objective-C开发:从HTTP请求到文件存储的实战
|
6月前
|
存储 缓存 网络协议
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点、状态码、报文格式,GET、POST的区别,DNS的解析过程、数字证书、Cookie与Session,对称加密和非对称加密
|
7月前
|
SQL 安全 关系型数据库
第三次面试总结 - 吉云集团 - 全栈开发
本文是作者对吉云集团全栈开发岗位的第三次面试总结,面试结果非常好,内容全面覆盖了Java基础、MySQL和项目经验,作者认为自己的MySQL基础知识稍弱,需要加强。
78 0
第三次面试总结 - 吉云集团 - 全栈开发