热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Retrofit2.0源码分析

本文转载自Carson_Ho的文章:手把手带你深入剖析Retrofit2.0源码前言在Andrroid开发中,网络请求十分常用而在Android网络请

本文转载自Carson_Ho的文章:手把手带你深入剖析 Retrofit 2.0 源码

前言
  • Andrroid开发中,网络请求十分常用
  • 而在Android网络请求库中,Retrofit是当下最热的一个网络请求库

步骤2

我们先来看Builder类

请按下面提示的步骤进行查看

<-- Builder类-->
public static final class Builder {private Platform platform;private okhttp3.Call.Factory callFactory;private HttpUrl baseUrl;private List converterFactories &#61; new ArrayList<>();private List adapterFactories &#61; new ArrayList<>();private Executor callbackExecutor;private boolean validateEagerly;// 从上面可以发现&#xff0c; Builder类的成员变量与Retrofit类的成员变量是对应的
// 所以Retrofit类的成员变量基本上是通过Builder类进行配置
// 开始看步骤1<-- 步骤1 -->
// Builder的构造方法&#xff08;无参&#xff09;public Builder() {this(Platform.get());
// 用this调用自己的有参构造方法public Builder(Platform platform) ->>步骤5&#xff08;看完步骤2、3、4再看&#xff09;
// 并通过调用Platform.get&#xff08;&#xff09;传入了Platform对象
// 继续看Platform.get()方法 ->>步骤2
// 记得最后继续看步骤5的Builder有参构造方法}
...
}<-- 步骤2 -->
class Platform {private static final Platform PLATFORM &#61; findPlatform();// 将findPlatform()赋给静态变量static Platform get() {return PLATFORM; // 返回静态变量PLATFORM&#xff0c;即findPlatform() ->>步骤3}<-- 步骤3 -->
private static Platform findPlatform() {try {Class.forName("android.os.Build");// Class.forName(xxx.xx.xx)的作用&#xff1a;要求JVM查找并加载指定的类&#xff08;即JVM会执行该类的静态代码段&#xff09;if (Build.VERSION.SDK_INT !&#61; 0) {return new Android(); // 此处表示&#xff1a;如果是Android平台&#xff0c;就创建并返回一个Android对象 ->>步骤4}} catch (ClassNotFoundException ignored) {}try {// 支持Java平台Class.forName("java.util.Optional");return new Java8();} catch (ClassNotFoundException ignored) {}try {// 支持iOS平台Class.forName("org.robovm.apple.foundation.NSObject");return new IOS();} catch (ClassNotFoundException ignored) {}// 从上面看出&#xff1a;Retrofit2.0支持3个平台&#xff1a;Android平台、Java平台、IOS平台
// 最后返回一个Platform对象&#xff08;指定了Android平台&#xff09;给Builder的有参构造方法public Builder(Platform platform) --> 步骤5
// 说明Builder指定了运行平台为Androidreturn new Platform();}
...
}<-- 步骤4 -->
// 用于接收服务器返回数据后进行线程切换在主线程显示结果static class Android extends Platform {&#64;OverrideCallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {return new ExecutorCallAdapterFactory(callbackExecutor);// 创建默认的网络请求适配器工厂// 该默认工厂生产的 adapter 会使得Call在异步调用时在指定的 Executor 上执行回调// 在Retrofit中提供了四种CallAdapterFactory&#xff1a; ExecutorCallAdapterFactory&#xff08;默认&#xff09;、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory// 采用了策略模式}&#64;Override public Executor defaultCallbackExecutor() {// 返回一个默认的回调方法执行器// 该执行器作用&#xff1a;切换线程&#xff08;子->>主线程&#xff09;&#xff0c;并在主线程&#xff08;UI线程&#xff09;中执行回调方法return new MainThreadExecutor();}static class MainThreadExecutor implements Executor {private final Handler handler &#61; new Handler(Looper.getMainLooper());// 获取与Android 主线程绑定的Handler &#64;Override public void execute(Runnable r) {handler.post(r);// 该Handler是上面获取的与Android 主线程绑定的Handler // 在UI线程进行对网络请求返回数据处理等操作。}}// 切换线程的流程&#xff1a;
// 1. 回调ExecutorCallAdapterFactory生成了一个ExecutorCallbackCall对象
//2. 通过调用ExecutorCallbackCall.enqueue(CallBack)从而调用MainThreadExecutor的execute()通过handler切换到主线程}// 下面继续看步骤5的Builder有参构造方法
<-- 步骤5 -->
// Builder类的构造函数2&#xff08;有参&#xff09;public Builder(Platform platform) {// 接收Platform对象&#xff08;Android平台&#xff09;this.platform &#61; platform;// 通过传入BuiltInConverters()对象配置数据转换器工厂&#xff08;converterFactories&#xff09;// converterFactories是一个存放数据转换器Converter.Factory的数组
// 配置converterFactories即配置里面的数据转换器converterFactories.add(new BuiltInConverters());// BuiltInConverters是一个内置的数据转换器工厂&#xff08;继承Converter.Factory类&#xff09;
// new BuiltInConverters()是为了初始化数据转换器}

对Builder类分析完毕&#xff0c;总结&#xff1a;Builder设置了默认的

  • 平台类型对象&#xff1a;Android
  • 网络请求适配器工厂&#xff1a;CallAdapterFactory

    CallAdapter用于对原始Call进行再次封装&#xff0c;如Call到Observable

  • 数据转换器工厂&#xff1a; converterFactory

  • 回调执行器&#xff1a;callbackExecutor

特别注意&#xff0c;这里只是设置了默认值&#xff0c;但未真正配置到具体的Retrofit类的成员变量当中

步骤3

Paste_Image.png

步骤1&#xff1a;ServiceMethod类 构造函数

Paste_Image.png


<-- ServiceMethod 类 -->
public final class ServiceMethod {
final okhttp3.Call.Factory callFactory; // 网络请求工厂
final CallAdapter callAdapter;
// 网络请求适配器工厂
// 具体创建是在new ServiceMethod.Builder(this, method).build()最后的build()中
// 下面会详细说明private final Converter responseConverter;
// Response内容转换器
// 作用&#xff1a;负责把服务器返回的数据&#xff08;JSON或者其他格式&#xff0c;由 ResponseBody 封装&#xff09;转化为 T 类型的对象&#xff1b;private final HttpUrl baseUrl; // 网络请求地址
private final String relativeUrl; // 网络请求的相对地址
private final String httpMethod; // 网络请求的Http方法
private final Headers headers; // 网络请求的http请求头 键值对
private final MediaType contentType; // 网络请求的http报文body的类型 private final ParameterHandler[] parameterHandlers; // 方法参数处理器// 作用&#xff1a;负责解析 API 定义时每个方法的参数&#xff0c;并在构造 HTTP 请求时设置参数&#xff1b;// 下面会详细说明// 说明&#xff1a;从上面的成员变量可以看出&#xff0c;ServiceMethod对象包含了访问网络的所有基本信息<-- ServiceMethod 类的构造函数 -->
// 作用&#xff1a;传入各种网络请求参数
ServiceMethod(Builder builder) {this.callFactory &#61; builder.retrofit.callFactory(); this.callAdapter &#61; builder.callAdapter; this.responseConverter &#61; builder.responseConverter; this.baseUrl &#61; builder.retrofit.baseUrl(); this.relativeUrl &#61; builder.relativeUrl; this.httpMethod &#61; builder.httpMethod; this.headers &#61; builder.headers; this.contentType &#61; builder.contentType; . this.hasBody &#61; builder.hasBody; y this.isFormEncoded &#61; builder.isFormEncoded; this.isMultipart &#61; builder.isMultipart; this.parameterHandlers &#61; builder.parameterHandlers;
}

步骤2&#xff1a;ServiceMethod的Builder&#xff08;



public Builder(Retrofit retrofit, Method method) {this.retrofit &#61; retrofit;this.method &#61; method;// 获取网络请求接口方法里的注释this.methodAnnotations &#61; method.getAnnotations();// 获取网络请求接口方法里的参数类型 this.parameterTypes &#61; method.getGenericParameterTypes(); //获取网络请求接口方法里的注解内容 this.parameterAnnotationsArray &#61; method.getParameterAnnotations(); }

步骤3&#xff1a;ServiceMethod的build&#xff08;&#xff09;

Paste_Image.png


// 作用&#xff1a;控制ServiceMethod对象的生成流程public ServiceMethod build() {callAdapter &#61; createCallAdapter(); // 根据网络请求接口方法的返回值和注解类型&#xff0c;从Retrofit对象中获取对应的网络请求适配器 -->关注点1responseType &#61; callAdapter.responseType(); // 根据网络请求接口方法的返回值和注解类型&#xff0c;从Retrofit对象中获取该网络适配器返回的数据类型responseConverter &#61; createResponseConverter(); // 根据网络请求接口方法的返回值和注解类型&#xff0c;从Retrofit对象中获取对应的数据转换器 -->关注点3// 构造 HTTP 请求时&#xff0c;我们传递的参数都是String// Retrofit 类提供 converter把传递的参数都转化为 String // 其余类型的参数都利用 Converter.Factory 的stringConverter 进行转换// &#64;Body 和 &#64;Part 类型的参数利用Converter.Factory 提供的 requestBodyConverter 进行转换// 这三种 converter 都是通过“询问”工厂列表进行提供&#xff0c;而工厂列表我们可以在构造 Retrofit 对象时进行添加。for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);}// 解析网络请求接口中方法的注解// 主要是解析获取Http请求的方法// 注解包括&#xff1a;DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTTP、retrofit2.http.Headers、Multipart、FormUrlEncoded// 处理主要是调用方法 parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) ServiceMethod中的httpMethod、hasBody、relativeUrl、relativeUrlParamNames域进行赋值int parameterCount &#61; parameterAnnotationsArray.length;// 获取当前方法的参数数量parameterHandlers &#61; new ParameterHandler[parameterCount];for (int p &#61; 0; p // 为方法中的每个参数创建一个ParameterHandler对象并解析每个参数使用的注解类型// 该对象的创建过程就是对方法参数中注解进行解析// 这里的注解包括&#xff1a;Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url parameterHandlers[p] &#61; parseParameter(p, parameterType, parameterAnnotations);} return new ServiceMethod<>(this);<-- 总结 -->
// 1. 根据返回值类型和方法标注从Retrofit对象的的网络请求适配器工厂集合和内容转换器工厂集合中分别获取到该方法对应的网络请求适配器和Response内容转换器&#xff1b;
// 2. 根据方法的标注对ServiceMethod的域进行赋值
// 3. 最后为每个方法的参数的标注进行解析&#xff0c;获得一个ParameterHandler对象
// 该对象保存有一个Request内容转换器——根据参数的类型从Retrofit的内容转换器工厂集合中获取一个Request内容转换器或者一个String内容转换器。}<-- 关注点1&#xff1a;createCallAdapter() -->private CallAdapter createCallAdapter() {// 获取网络请求接口里方法的返回值类型Type returnType &#61; method.getGenericReturnType(); // 获取网络请求接口接口里的注解// 此处使用的是&#64;GetAnnotation[] annotations &#61; method.getAnnotations(); try {return retrofit.callAdapter(returnType, annotations); // 根据网络请求接口方法的返回值和注解类型&#xff0c;从Retrofit对象中获取对应的网络请求适配器// 下面会详细说明retrofit.callAdapter&#xff08;&#xff09; -- >关注点2}
...<-- 关注点2&#xff1a;retrofit.callAdapter() -->public CallAdapter callAdapter(Type returnType, Annotation[] annotations) {return nextCallAdapter(null, returnType, annotations);}public CallAdapter nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,Annotation[] annotations) {// 创建 CallAdapter 如下// 遍历 CallAdapter.Factory 集合寻找合适的工厂&#xff08;该工厂集合在第一步构造 Retrofit 对象时进行添加&#xff08;第一步时已经说明&#xff09;&#xff09;// 如果最终没有工厂提供需要的 CallAdapter&#xff0c;将抛出异常for (int i &#61; start, count &#61; adapterFactories.size(); i adapter &#61; adapterFactories.get(i).get(returnType, annotations, this); if (adapter !&#61; null) {return adapter;}}<-- 关注点3&#xff1a;createResponseConverter&#xff08;&#xff09; -->private Converter createResponseConverter() {Annotation[] annotations &#61; method.getAnnotations();try {// responseConverter 还是由 Retrofit 类提供 -->关注点4return retrofit.responseBodyConverter(responseType, annotations);} catch (RuntimeException e) { throw methodError(e, "Unable to create converter for %s", responseType);}}<-- 关注点4&#xff1a;responseBodyConverter&#xff08;&#xff09; -->public Converter responseBodyConverter(Type type, Annotation[] annotations) {return nextResponseBodyConverter(null, type, annotations);}public Converter nextResponseBodyConverter(Converter.Factory skipPast,int start &#61; converterFactories.indexOf(skipPast) &#43; 1;for (int i &#61; start, count &#61; converterFactories.size(); i // 获取Converter 过程&#xff1a;&#xff08;和获取 callAdapter 基本一致&#xff09;Converter converter &#61;converterFactories.get(i).responseBodyConverter(type, annotations, this); // 遍历 Converter.Factory 集合并寻找合适的工厂&#xff08;该工厂集合在构造 Retrofit 对象时进行添加&#xff08;第一步时已经说明&#xff09;&#xff09;// 由于构造Retroifit采用的是Gson解析方式&#xff0c;所以取出的是GsonResponseBodyConverter// Retrofit - Converters 还提供了 JSON&#xff0c;XML&#xff0c;ProtoBuf 等类型数据的转换功能。// 继续看responseBodyConverter&#xff08;&#xff09; -->关注点5 }<-- 关注点5&#xff1a;responseBodyConverter&#xff08;&#xff09; -->
&#64;Override
public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {TypeAdapter adapter &#61; gson.getAdapter(TypeToken.get(type));// 根据目标类型&#xff0c;利用 Gson#getAdapter 获取相应的 adapterreturn new GsonResponseBodyConverter<>(gson, adapter);
}// 做数据转换时调用 Gson 的 API 即可。
final class GsonResponseBodyConverter implements Converter {private final Gson gson;private final TypeAdapter adapter;GsonResponseBodyConverter(Gson gson, TypeAdapter adapter) {this.gson &#61; gson;this.adapter &#61; adapter;}&#64;Override public T convert(ResponseBody value) throws IOException {JsonReader jsonReader &#61; gson.newJsonReader(value.charStream());try {return adapter.read(jsonReader);} finally {value.close();}}
}

  • 当选择了RxjavaCallAdapterFactory后&#xff0c;Rxjava通过策略模式选择对应的adapter 
    关于策略模式的讲解&#xff0c;请看文章策略模式&#xff08;Strategy Pattern&#xff09;- 最易懂的设计模式解析
  • 具体过程是&#xff1a;根据网络接口方法的返回值类型来选择具体要用哪种CallAdapterFactory&#xff0c;然后创建具体的CallAdapter实例

采用工厂模式使得各功能模块高度解耦

  • 上面提到了两种工厂&#xff1a;CallAdapter.Factory & Converter.Factory分别负责提供不同的功能模块
  • 工厂负责如何提供、提供何种功能模块
  • Retrofit 只负责提供选择何种工厂的决策信息&#xff08;如网络接口方法的参数、返回值类型、注解等&#xff09;

这正是所谓的高内聚低耦合&#xff0c;工厂模式get。

关于工厂模式请看我写的文章&#xff1a; 
简单工厂模式&#xff08;SimpleFactoryPattern&#xff09;- 最易懂的设计模式解析 
工厂方法模式&#xff08;Factory Method&#xff09;- 最易懂的设计模式解析 
抽象工厂模式&#xff08;Abstract Factory&#xff09;- 最易懂的设计模式解析

终于配置完网络请求参数&#xff08;即配置好ServiceMethod对象&#xff09;。接下来将讲解第二行代码&#xff1a;okHttpCall对象的创建

第二行&#xff1a;OkHttpCall okHttpCall &#61; new OkHttpCall<>(serviceMethod, args);

根据第一步配置好的ServiceMethod对象和输入的请求参数创建okHttpCall对象

<--OkHttpCall类 -->
public class OkHttpCall {private final ServiceMethod serviceMethod; // 含有所有网络请求参数信息的对象 private final Object[] args; // 网络请求接口的参数 private okhttp3.Call rawCall; //实际进行网络访问的类 private Throwable creationFailure; //几个状态标志位 private boolean executed; private volatile boolean canceled; <--OkHttpCall构造函数 -->public OkHttpCall(ServiceMethod serviceMethod, Object[] args) { // 传入了配置好的ServiceMethod对象和输入的请求参数this.serviceMethod &#61; serviceMethod; this.args &#61; args;
}

第三行&#xff1a;return serviceMethod.callAdapter.adapt(okHttpCall);

将第二步创建的OkHttpCall对象传给第一步创建的serviceMethod对象中对应的网络请求适配器工厂的adapt&#xff08;&#xff09;

返回对象类型&#xff1a;Android默认的是Call<>&#xff1b;若设置了RxJavaCallAdapterFactory&#xff0c;返回的则是Observable<>

<-- adapt&#xff08;&#xff09;详解-->
public Call adapt(Call call) {return new ExecutorCallbackCall<>(callbackExecutor, call); }ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {this.delegate &#61; delegate; // 把上面创建并配置好参数的OkhttpCall对象交给静态代理delegate// 静态代理和动态代理都属于代理模式// 静态代理作用&#xff1a;代理执行被代理者的方法&#xff0c;且可在要执行的方法前后加入自己的动作&#xff0c;进行对系统功能的拓展this.callbackExecutor &#61; callbackExecutor;// 传入上面定义的回调方法执行器// 用于进行线程切换 }

  • 采用了装饰模式&#xff1a;ExecutorCallbackCall &#61; 装饰者&#xff0c;而里面真正去执行网络请求的还是OkHttpCall
  • 使用装饰模式的原因&#xff1a;希望在OkHttpCall发送请求时做一些额外操作。这里的额外操作是线程转换&#xff0c;即将子线程切换到主线程 
    1. OkHttpCall的enqueue()是进行网络异步请求的&#xff1a;当你调用OkHttpCall.enqueue&#xff08;&#xff09;时&#xff0c;回调的callback是在子线程中&#xff0c;需要通过Handler转换到主线程进行回调。ExecutorCallbackCall就是用于线程回调&#xff1b; 
    2. 当然以上是原生Retrofit使用的切换线程方式。如果你用Rxjava&#xff0c;那就不会用到这个ExecutorCallbackCall而是RxJava的Call&#xff0c;此处不过多展开

步骤4讲解&#xff1a;Call call &#61; NetService.getCall();

  • NetService对象实际上是动态代理对象Proxy.newProxyInstance&#xff08;&#xff09;&#xff08;步骤3中已说明&#xff09;&#xff0c;并不是真正的网络请求接口创建的对象
  • NetService对象调用getCall&#xff08;&#xff09;时会被动态代理对象Proxy.newProxyInstance&#xff08;&#xff09;拦截&#xff0c;然后调用自身的InvocationHandler # invoke&#xff08;&#xff09;
  • invoke(Object proxy, Method method, Object... args)会传入3个参数&#xff1a;Object proxy:&#xff08;代理对象&#xff09;、 
    Method method&#xff08;调用的getCall()&#xff09; 
    Object... args&#xff08;方法的参数&#xff0c;即getCall&#xff08;*&#xff09;中的*&#xff09;
  • 接下来利用Java反射获取到getCall&#xff08;&#xff09;的注解信息&#xff0c;配合args参数创建ServiceMethod对象。 

    如上面步骤3描述&#xff0c;此处不再次讲解


最终创建并返回一个OkHttpCall类型的Call对象 
1. OkHttpCall类是OkHttp的包装类 
2. 创建了OkHttpCall类型的Call对象还不能发送网络请求&#xff0c;需要创建Request对象才能发送网络请求

总结

Retrofit采用了 外观模式 统一调用创建网络请求接口实例和网络请求参数配置的方法&#xff0c;具体细节是&#xff1a;

  • 动态创建网络请求接口的实例&#xff08;代理模式 - 动态代理&#xff09;
  • 创建 serviceMethod 对象&#xff08;建造者模式 & 单例模式&#xff08;缓存机制&#xff09;&#xff09;
  • 对 serviceMethod 对象进行网络请求参数配置&#xff1a;通过解析网络请求接口方法的参数、返回值和注解类型&#xff0c;从Retrofit对象中获取对应的网络请求的url地址、网络请求执行器、网络请求适配器 & 数据转换器。&#xff08;策略模式&#xff09;
  • 对 serviceMethod 对象加入线程切换的操作&#xff0c;便于接收数据后通过Handler从子线程切换到主线程从而对返回数据结果进行处理&#xff08;装饰模式&#xff09;
  • 最终创建并返回一个OkHttpCall类型的网络请求对象

3. 执行网络请求
  • Retrofit默认使用OkHttp&#xff0c;即OkHttpCall类&#xff08;实现了 retrofit2.Call接口&#xff09; 

    但可以自定义选择自己需要的Call类

  • OkHttpCall提供了两种网络请求方式&#xff1a; 
    1. 同步请求&#xff1a;OkHttpCall.execute()
    2. 异步请求&#xff1a;OkHttpCall.enqueue()

下面将详细介绍这两种网络请求方式。 
对于OkHttpCall的enqueue&#xff08;&#xff09;、execute&#xff08;&#xff09;此处不往下分析&#xff0c;有兴趣的读者可以看OkHttp的源码

3.1 同步请求OkHttpCall.execute()

3.1.1 发送请求过程

  • 步骤1&#xff1a;对网络请求接口的方法中的每个参数利用对应ParameterHandler进行解析&#xff0c;再根据ServiceMethod对象创建一个OkHttpRequest对象
  • 步骤2&#xff1a;使用OkHttpRequest发送网络请求&#xff1b;
  • 步骤3&#xff1a;对返回的数据使用之前设置的数据转换器&#xff08;GsonConverterFactory&#xff09;解析返回的数据&#xff0c;最终得到一个Response对象

3.1.2 具体使用

Response response &#61; call.execute();

  • 1

上面简单的一行代码&#xff0c;其实包含了整个发送网络同步请求的三个步骤。

3.1.3 源码分析

&#64;Override
public Response execute() throws IOException {okhttp3.Call call;// 设置同步锁synchronized (this) {call &#61; rawCall;if (call &#61;&#61; null) {try {call &#61; rawCall &#61; createRawCall();// 步骤1&#xff1a;创建一个OkHttp的Request对象请求 -->关注1} catch (IOException | RuntimeException e) {creationFailure &#61; e;throw e;}}}return parseResponse(call.execute());// 步骤2&#xff1a;调用OkHttpCall的execute()发送网络请求&#xff08;同步&#xff09;// 步骤3&#xff1a;解析网络请求返回的数据parseResponse&#xff08;&#xff09; -->关注2
}<-- 关注1&#xff1a;createRawCall() -->
private okhttp3.Call createRawCall() throws IOException {Request request &#61; serviceMethod.toRequest(args);// 从ServiceMethod的toRequest&#xff08;&#xff09;返回一个Request对象okhttp3.Call call &#61; serviceMethod.callFactory.newCall(request);// 根据serviceMethod和request对象创建 一个okhttp3.Requestif (call &#61;&#61; null) {throw new NullPointerException("Call.Factory returned null.");}return call;
}<-- 关注2&#xff1a;parseResponse&#xff08;&#xff09;-->
Response parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody &#61; rawResponse.body();rawResponse &#61; rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();// 收到返回数据后进行状态码检查// 具体关于状态码说明下面会详细介绍int code &#61; rawResponse.code();if (code <200 || code >&#61; 300) {}if (code &#61;&#61; 204 || code &#61;&#61; 205) {return Response.success(null, rawResponse);}ExceptionCatchingRequestBody catchingBody &#61; new ExceptionCatchingRequestBody(rawBody);try {T body &#61; serviceMethod.toResponse(catchingBody);// 等Http请求返回后 & 通过状态码检查后&#xff0c;将response body传入ServiceMethod中&#xff0c;ServiceMethod通过调用Converter接口&#xff08;之前设置的GsonConverterFactory&#xff09;将response body转成一个Java对象&#xff0c;即解析返回的数据// 生成Response类return Response.success(body, rawResponse);} catch (RuntimeException e) {... // 异常处理}
}

特别注意&#xff1a;

    • ServiceMethod几乎保存了一个网络请求所需要的数据
    • 发送网络请求时&#xff0c;OkHttpCall需要从ServiceMethod中获得一个Request对象
    • 解析数据时&#xff0c;还需要通过ServiceMethod使用Converter&#xff08;数据转换器&#xff09;转换成Java对象进行数据解析

    • 为了提高效率&#xff0c;Retrofit还会对解析过的请求ServiceMethod进行缓存&#xff0c;存放在Map serviceMethodCache &#61; new LinkedHashMap<>();对象中&#xff0c;即第二步提到的单例模式

    • 关于状态码检查时的状态码说明&#xff1a;

  • Retrofit源码分析图




推荐阅读
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
author-avatar
神秘雯泽芳子
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有