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;
【附】相关架构及资料

相关文章
|
19天前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
139 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
26天前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
208 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
27天前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
409 3
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
2月前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
418 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
|
24天前
|
移动开发 Android开发
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
88 0
|
2月前
|
Java 开发工具 Maven
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
161 6
|
5月前
|
JSON 中间件 Go
Go 网络编程:HTTP服务与客户端开发
Go 语言的 `net/http` 包功能强大,可快速构建高并发 HTTP 服务。本文从创建简单 HTTP 服务入手,逐步讲解请求与响应对象、URL 参数处理、自定义路由、JSON 接口、静态文件服务、中间件编写及 HTTPS 配置等内容。通过示例代码展示如何使用 `http.HandleFunc`、`http.ServeMux`、`http.Client` 等工具实现常见功能,帮助开发者掌握构建高效 Web 应用的核心技能。
295 61
|
4月前
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
299 11
|
5月前
|
C# 图形学 开发者
Unity开发中使用UnityWebRequest从HTTP服务器下载资源。
总之,UnityWebRequest就是游戏开发者手中的万能钓鱼竿,既可以获取文本数据,也能钓上图片资源,甚至是那声音的涟漪。使用UnityWebRequest的时候,你需要精心准备,比如确定URL、配置请求类型和头信息;发起请求;巧妙处理钓获的数据;还需要机智面对网络波澜,处理各种可能出现的错误。按照这样的过程,数据的钓取将会是一次既轻松愉快也效率高效的编程钓鱼之旅。
247 18
|
4月前
|
移动开发 Java 编译器
Kotlin与Jetpack Compose:Android开发生态的演进与架构思考
本文从资深Android工程师视角深入分析Kotlin与Jetpack Compose在Android系统中的技术定位。Kotlin通过空安全、协程等特性解决了Java在移动开发中的痛点,成为Android官方首选语言。Jetpack Compose则引入声明式UI范式,通过重组机制实现高效UI更新。两者结合不仅提升开发效率,更为跨平台战略和现代架构模式提供技术基础,代表了Android开发生态的根本性演进。
149 0

热门文章

最新文章