Retrofit2 源码解析,面试的时候突然遇到答不上的问题怎么办

private final ParameterHandler<?>[] parameterHandlers;

ServiceMethod(Builder<R, T> builder) {

this.callFactory = builder.retrofit.callFactory();

this.callAdapter = builder.callAdapter;

this.baseUrl = builder.retrofit.baseUrl();

this.responseConverter = builder.responseConverter;

this.httpMethod = builder.httpMethod;

this.relativeUrl = builder.relativeUrl;

this.headers = builder.headers;

this.contentType = builder.contentType;

this.hasBody = builder.hasBody;

this.isFormEncoded = builder.isFormEncoded;

this.isMultipart = builder.isMultipart;

this.parameterHandlers = builder.parameterHandlers;

}

// … 省略部分代码

首先看看 ServiceMethod 的构造方法。 也是通过建造者模式构建的。其中很多变量其实都很熟悉了,比如 callFactory 、 baseUrl 。 对于 callAdapter、responseConverter 我们别弄混了,我们在 Retrofit 类中的变量是 callAdapterFactories 和 converterFactories , 是它们的工厂,是生产它们的地方。

接下来看 Builder 吧,毕竟这是真正做事的。

public ServiceMethod build() {

// 拿到具体的 CallAdapter 即 网络请求适配器,具体看 3.1.1.1

callAdapter = createCallAdapter();

// 根据上面拿到的 callAdapter 获取 响应类型,在 3.1.1.1 小节分析完后可知道

// 在我们的例子中 responseType = java.util.List<java.lang.Integer>

responseType = callAdapter.responseType();

if (responseType == Response.class || responseType == okhttp3.Response.class) {

throw methodError(“'”

  • Utils.getRawType(responseType).getName()

  • “’ is not a valid response body type. Did you mean ResponseBody?”);

}

// 获取 响应转换器 ,具体看 3.1.1.2 小节

responseConverter = createResponseConverter();

// 解析网络请求接口中方法的注解,这里我们就只有一个 @GET 注解,具体看 3.1.1.3 小节

// 这里解析完可以拿到 Http 请求方法、请求体、相对 url、相对 url 中的参数

for (Annotation annotation : methodAnnotations) {

parseMethodAnnotation(annotation);

}

//解析完方法上的注解后,做校验

if (httpMethod == null) {

throw methodError(“HTTP method annotation is required (e.g., @GET, @POST, etc.).”);

}

if (!hasBody) {

if (isMultipart) {

throw methodError(

“Multipart can only be specified on HTTP methods with request body (e.g., @POST).”);

}

if (isFormEncoded) {

throw methodError("FormUrlEncoded can only be specified on HTTP methods with "

  • “request body (e.g., @POST).”);

}

}

// 解析当前方法的参数,这里就我们的例子而言

// parameterAnnotationsArray 就是 @Path ,所以这里的 length 就是 1

int parameterCount = parameterAnnotationsArray.length;

parameterHandlers = new ParameterHandler<?>[parameterCount];

for (int p = 0; p < parameterCount; p++) {

// parameterTypes 是参数类型,就本例而言是 String

Type parameterType = parameterTypes[p];

if (Utils.hasUnresolvableType(parameterType)) {

throw parameterError(p, “Parameter type must not include a type variable or wildcard: %s”,

parameterType);

}

// 拿到第一个参数的 注解数组

Annotation[] parameterAnnotations = parameterAnnotationsArray[p];

if (parameterAnnotations == null) {

throw parameterError(p, “No Retrofit annotation found.”);

}

// 解析参数

// p : 0

// parameterType : String

// parameterAnnotations : 虽然是数组,但是就一个元素 @Path

// 这个 parseParameter 就不分析了,大家自己看看源码就清楚了,无非就是构建 ParameterHandler 数组,而这个 ParameterHandler 其实就是负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数

parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);

}

// 解析完方法中参数的注解后,做校验

if (relativeUrl == null && !gotUrl) {

throw methodError(“Missing either @%s URL or @Url parameter.”, httpMethod);

}

if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {

throw methodError(“Non-body HTTP method cannot contain @Body.”);

}

if (isFormEncoded && !gotField) {

throw methodError(“Form-encoded method must contain at least one @Field.”);

}

if (isMultipart && !gotPart) {

throw methodError(“Multipart method must contain at least one @Part.”);

}

return new ServiceMethod<>(this);

}

3.1.1.1 createCallAdapter ()

private CallAdapter<T, R> createCallAdapter() {

// 拿到网络请求接口里方法的返回值类型,在我们的例子中会返回如下类型

// retrofit2.Call<java.util.List<java.lang.Integer>>

Type returnType = method.getGenericReturnType();

if (Utils.hasUnresolvableType(returnType)) {

throw methodError(

“Method return type must not include a type variable or wildcard: %s”, returnType);

}

// 如果返回类型是 void ,抛出异常

if (returnType == void.class) {

throw methodError(“Service methods cannot return void.”);

}

// 拿到方法的 注解 ,在我们的例子中就是如下所示,大家可以自己实验下

// @retrofit2.http.GET(value=users/{user}/repos)

Annotation[] annotations = method.getAnnotations();

try {

// 拿到注解后,返回个 CallAdapter ,跟进去看看究竟是做了什么

return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);

} catch (RuntimeException e) { // Wide exception range because factories are user code.

throw methodError(e, “Unable to create call adapter for %s”, returnType);

}

}

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {

// 这里会去调用 nextCallAdapter

return nextCallAdapter(null, returnType, annotations);

}

// 这里的参数大家注意

// skipPast 上面传的是 null

// returnType 就是 retrofit2.Call<java.util.List<java.lang.Integer>>

// annotations 在我们的例子中就是 @retrofit2.http.GET(value=users/{user}/repos)

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {

checkNotNull(returnType, “returnType == null”);

checkNotNull(annotations, “annotations == null”);

// callAdapterFactories 是一个 ArrayList 对象,里面存放着一个 ExecutorCallAdapterFactory 对象 ,这个是在 Retrofit Builder 的时候创建的,也就是我们上面所说的生产 CallAdapter 的地方,大家可以回过头去看看。 这里的 skipPast 是null, 所以 indexOf 肯定返回的 -1, 所以这里 start = 0

int start = callAdapterFactories.indexOf(skipPast) + 1;

// 循环, 这里由于我们的 callAdapterFactories 只有一个 元素, 所以直接看 ExecutorCallAdapterFactory 的 get方法

for (int i = start, count = callAdapterFactories.size(); i < count; i++) {

CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);

if (adapter != null) {

return adapter;

}

}

// 错误信息 builder

StringBuilder builder = new StringBuilder("Could not locate call adapter for ")

.append(returnType)

.append(“.\n”);

if (skipPast != null) {

builder.append(" Skipped:");

for (int i = 0; i < start; i++) {

builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());

}

builder.append(‘\n’);

}

builder.append(" Tried:");

for (int i = start, count = callAdapterFactories.size(); i < count; i++) {

builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());

}

throw new IllegalArgumentException(builder.toString());

}

到这里,我们别忘了我们是在干嘛,我们是在获取 CallAdapter<T, R> ,好了,继续看 ExecutorCallAdapterFactory 的 get 方法。 解释都在代码注释里哟,一定要看看才知道现在到底是在干啥。话说源码分析,还是得靠自己认认真真读一次源码才行。

@Override

public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {

// getRawType 会返回该类型的原始类类型 , 比如传进去的是 List<? extends Runnable> 会返回 List.class

// 那么在我们的例子中,我们的 returnType 是 retrofit2.Call<java.util.List<java.lang.Integer>>

// 那么 getRawType 后,返回的是 retrofit2.Call ,所以这里是相等的

if (getRawType(returnType) != Call.class) {

return null;

}

// 根据 returnType 拿到 responseType ,这里就不跟进了,可以自己去看看

// 在我们的例子中, responseType = java.util.List<java.lang.Integer>

final Type responseType = Utils.getCallResponseType(returnType);

// 最后返回一个 CallAdapter

return new CallAdapter<Object, Call<?>>() {

@Override public Type responseType() {

return responseType;

}

@Override public Call adapt(Call call) {

return new ExecutorCallbackCall<>(callbackExecutor, call);

}

};

}

到这里,其实我们大概知道这个 CallAdapter 有什么用了,就是提供两个东西

  • 网络请求响应要返回的类型 responseType

  • retrofit2.Call< T > ,注意这里不是 okhttp3 下的 Call ,这里暂不深究。

因为我们不要忘了现在在做什么,我们现在是在获取 ServiceMethod 中的 callAdapter 变量值。所以看到这里返回了一个 CallAdapter 对象即可。

3.1.1.2 createResponseConverter ()

这里个方法是获取 响应转换器, 就是把网络请求得到的响应数据转换成相应的格式。

private Converter<ResponseBody, T> createResponseConverter() {

// 拿到方法上所有的注解,在我们的例子中就只有 @GET 注解

Annotation[] annotations = method.getAnnotations();

// 这里的 responseType 就是上面我们得到的 List

try {

return retrofit.responseBodyConverter(responseType, annotations);

} catch (RuntimeException e) { // Wide exception range because factories are user code.

throw methodError(e, “Unable to create converter for %s”, responseType);

}

}

这里想必大家也知道套路了,跟获取 CallAdapter 是一样的,代码就不贴了,代码里同样是循环遍历 Retrofit 里的 converterFactories 变量。而这个 converterFactories 在我们的例子中是没有设置转换器的,所以它也只有一个默认的元素,即 BuiltInConverters 。 那么我们直接查看 它的 responseBodyConverter 方法。

final class BuiltInConverters extends Converter.Factory {

// 注意这里的参数,别忘了到底是什么

// type : 就是我们的 responseType ,即 List

// annotations : 这里我们方法的注解只有一个,所以就是 @GET

@Override

public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,

Retrofit retrofit) {

if (type == ResponseBody.class) {

return Utils.isAnnotationPresent(annotations, Streaming.class)

? StreamingResponseBodyConverter.INSTANCE
BufferingResponseBodyConverter.INSTANCE;

}

if (type == Void.class) {

return VoidResponseBodyConverter.INSTANCE;

}

return null;

}

通过这里我们可以知道,其实它会返回 null 。 所以我们 ServiceMethod 中的 Builder 中的 responseConverter 变量就等于 null 。

3.1.1.3 parseMethodAnnotation ()

我们来看看 解析方法注解 ,注意我们例子中这个方法里传的参数是 @GET 注解

private void parseMethodAnnotation(Annotation annotation) {

if (annotation instanceof DELETE) {

parseHttpMethodAndPath(“DELETE”, ((DELETE) annotation).value(), false);

} else if (annotation instanceof GET) {

//我们这里是 GET 注解,所以进这个方法

parseHttpMethodAndPath(“GET”, ((GET) annotation).value(), false);

} else if (annotation instanceof HEAD) {

parseHttpMethodAndPath(“HEAD”, ((HEAD) annotation).value(), false);

if (!Void.class.equals(responseType)) {

throw methodError(“HEAD method must use Void as response type.”);

}

}

// 省略后续代码,后续还有很多其他类型的判断

}

// 这里的三个参数的值

// httpMethod : GET

// value : users/{user}/repos

// hasBody : false

private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {

// 此处判断 httpMethod 的值是否存在,说明只允许一个 HTTP 方法存在

if (this.httpMethod != null) {

throw methodError(“Only one HTTP method is allowed. Found: %s and %s.”,

this.httpMethod, httpMethod);

}

this.httpMethod = httpMethod;

this.hasBody = hasBody;

if (value.isEmpty()) {

return;

}

// 下面是解析 value 中的 相对 url

// Get the relative URL path and existing query string, if present.

int question = value.indexOf(‘?’);

if (question != -1 && question < value.length() - 1) {

// Ensure the query string does not have any named parameters.

String queryParams = value.substring(question + 1);

Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);

if (queryParamMatcher.find()) {

throw methodError("URL query string “%s” must not have replace block. "

  • “For dynamic query parameters use @Query.”, queryParams);

}

}

this.relativeUrl = value;

// 相对地址中的参数名字,这里不具体分析了,可以把结果告诉你

// 在我们的例子中 value = “users/{user}/repos”

// 这里的 relativeUrlParamNames 是个 Set 集合 ,里面只有一个元素 user 。

this.relativeUrlParamNames = parsePathParameters(value);

}

至此,我们的 Builder 把 Http 的方法以及它的 Url 给分析完了,现在只剩 参数解析了。参数解析在 ServiceMethod 的 build 方法里已经讲过了 ,记得看注释。

呼~ 终于讲完了 ServiceMethod 的构造。这么大篇幅,由此可以看出 ServiceMethod 这个类非常重要。现在来总结一下,我们究竟拥有了些什么。

  • callFactory : ExecutorCallAdapterFactory 实例

  • callAdapter : ExecutorCallAdapterFactory中的get 方法返回的 CallAdapter 实例

  • baseUrl : HttpUrl 实例

  • responseConverter : 由于我们没设置,所以为 null

  • httpMethod : 字符串 GET

  • relativeUrl :字符串 users/{user}/repos

  • headers : 没有设置 Headers ,所以为 null

  • contentType : null

  • hasBody : false

  • isFormEncoded : false

  • isMultipart : false

  • parameterHandlers : 就我们例子而已,该数组有一个元素,Path 对象,它是 ParameterHandler 抽象类里的一个静态内部类。

由此可以看出,ServiceMethod 对象包含了访问网络的所有基本信息。

好吧,接下来还是得继续前行,别忘了,我们构建 ServiceMethod 只是在 invoke 方法内,并且这还只是第一步。接下来看第二步。

3.2 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

这里是 new 一个 OkHttpCall 对象,这个 OkHttpCall 是 Retrofit 的 Call,它里面就是做请求的地方,会有 request、enqueue 等同步、异步请求方法,但是在这里面真正执行请求的是 okhttp3.Call ,即把请求委托给 okHttp 去执行。下面简要看看它的构造方法和一些成员变量吧,因为这里只是 new 操作,所以暂时不分析其余方法,用到的时候再看。

final class OkHttpCall implements Call {

// 含有所有网络请求参数信息的 ServiceMethod

private final ServiceMethod<T, ?> serviceMethod;

private final @Nullable Object[] args;

private volatile boolean canceled;

// 实际进行网络请求的 Call

private @Nullable okhttp3.Call rawCall;

@GuardedBy(“this”) // Either a RuntimeException, non-fatal Error, or IOException.

private @Nullable Throwable creationFailure;

@GuardedBy(“this”)

private boolean executed;

// 传入配置好的 ServiceMethod 和 请求参数

OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {

this.serviceMethod = serviceMethod;

this.args = args;

}

这样就把 OkHttpCall 给构建好了,接下来看第三步。

3.3 return serviceMethod.adapt(okHttpCall);

直接上代码

T adapt(Call call) {

return callAdapter.adapt(call);

}

这是 前面构建好的 ServiceMethod 中的 adapt 方法,会去调用 callAdapter 的 adapt 方法,我们知道 ServiceMethod 中的 callAdapter 是 ExecutorCallAdapterFactory中的get 方法返回的 CallAdapter 实例。而这个实例的 adapt 方法会返回一个 ExecutorCallbackCall 对象。

static final class ExecutorCallbackCall implements Call {

// 这里在之前创建ExecutorCallAdapterFactory时,就知道它的值了,就是 MainThreadExecutor ,用来切换线程的

final Executor callbackExecutor;

// 这就是刚刚传进来的 OkHttpCall

final Call delegate;

ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {

this.callbackExecutor = callbackExecutor;

this.delegate = delegate;

}

到这里为止,我们已经成功的返回了一个 Call<List<Integer>>

4. 调用 Call 的 enqueue

趁热打铁,我们执行异步请求,看看怎样切换线程的。

@Override

public void enqueue(final Callback callback) {

checkNotNull(callback, “callback == null”);

// 真正的 Call 去执行请求

delegate.enqueue(new Callback() {

@Override public void onResponse(Call call, final Response response) {

// 回调后 利用 MainThreadExecutor 中的 Handler 切换到主线程中去。

callbackExecutor.execute(new Runnable() {

@Override public void run() {

if (delegate.isCanceled()) {

// Emulate OkHttp’s behavior of throwing/delivering an IOException on cancellation.

callback.onFailure(ExecutorCallbackCall.this, new IOException(“Canceled”));

} else {

callback.onResponse(ExecutorCallbackCall.this, response);

}

}

});

}

@Override public void onFailure(Call call, final Throwable t) {

callbackExecutor.execute(new Runnable() {

@Override public void run() {

callback.onFailure(ExecutorCallbackCall.this, t);

}

});

}

});

}

可以看到是 delegate 执行了 enqueue 操作,而 delegate 就是我们的 OkHttpCall ,在 OkHttpCall 里的 enqueue 方法是这样工作的。

通过 okhttp3.Call call = serviceMethod.toCall(args); 构建一个真正执行请求的 Call ,即把请求交给 okhttp 去完成。而构建一个 Call 利用到了 ServiceMethod 中的 ParameterHandler 对象,这个对象是用来处理参数的。 它会把具体参数的值与 RequestBuilder 绑定起来。当然也用到了 ServiceMethod 自己,ServiceMethod 类似请求响应的大管家。

文末

初级工程师拿到需求会直接开始做,然后做着做着发现有问题了,要么技术实现不了,要么逻辑有问题。

而高级工程师拿到需求会考虑很多,技术的可行性?对现有业务有没有帮助?对现有技术架构的影响?扩展性如何?等等…之后才会再进行设计编码阶段。

而现在随着跨平台开发,混合式开发,前端开发之类的热门,Android开发者需要学习和掌握的技术也在不断的增加。

通过和一些行业里的朋友交流讨论,以及参考现在大厂面试的要求。我们花了差不多一个月时间整理出了这份Android高级工程师需要掌握的所有知识体系。你可以看下掌握了多少。

混合式开发,微信小程序。都是得学会并且熟练的

这些是Android相关技术的内核,还有Java进阶

高级进阶必备的一些技术。像移动开发架构项目实战等

Android前沿技术;包括了组件化,热升级和热修复,以及各种架构跟框架的详细技术体系

以上即是我们整理的Android高级工程师需要掌握的技术体系了。可能很多朋友觉得很多技术自己都会了,只是一些新的技术不清楚而已。应该没什么太大的问题。

而这恰恰是问题所在!为什么别人高级工程师能年限突破30万,而你只有十几万呢?

就因为你只需补充你自己认为需要的,但并不知道企业需要的。这个就特别容易造成差距。因为你的技术体系并不系统,是零碎的,散乱的。那么你凭什么突破30万年薪呢?

我这些话比较直接,可能会戳到一些人的玻璃心,但是我知道肯定会对一些人起到点醒的效果的。而但凡只要有人因为我的这份高级系统大纲以及这些话找到了方向,并且付出行动去提升自我,为了成功变得更加努力。那么我做的这些就都有了意义。

喜欢的话请帮忙转发点赞一下能让更多有需要的人看到吧。谢谢!

以上系统大纲里包含的所有技术资料,我这里都有的。可以免费分享给有需要的朋友!

资料领取方式:点击我的GitHub

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

万呢?

就因为你只需补充你自己认为需要的,但并不知道企业需要的。这个就特别容易造成差距。因为你的技术体系并不系统,是零碎的,散乱的。那么你凭什么突破30万年薪呢?

我这些话比较直接,可能会戳到一些人的玻璃心,但是我知道肯定会对一些人起到点醒的效果的。而但凡只要有人因为我的这份高级系统大纲以及这些话找到了方向,并且付出行动去提升自我,为了成功变得更加努力。那么我做的这些就都有了意义。

喜欢的话请帮忙转发点赞一下能让更多有需要的人看到吧。谢谢!

以上系统大纲里包含的所有技术资料,我这里都有的。可以免费分享给有需要的朋友!

资料领取方式:点击我的GitHub

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-oOAK3qJx-1710983981980)]
[外链图片转存中…(img-EPvLQ9XK-1710983981980)]
[外链图片转存中…(img-smth8Hh8-1710983981980)]
[外链图片转存中…(img-2dkoPRyf-1710983981981)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-ag7uowh0-1710983981981)]

  • 29
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值