Retrofit 系列文章导读:

  • Android Retrofit 源码系列(一)~ 原理剖析
  • Android Retrofit 源码系列(二)~ 自定义 CallAdapter
  • Android Retrofit 源码系列(三)~ 整合 RxJava、Coroutine 分析
  • Android Retrofit 源码系列(四)~ 文件上传
  • Android Retrofit 源码系列(五)~ 设计模式分析

概述

我们知道 Retrofit 网络框架在 Android 开发中的使用是非常普遍的,而且可以很方便的和 RxJava、Kotlin Coroutine 结合使用。

最近花了一些时间研究了一下 Retrofit 框架,从框架的使用到其实现原理研究了一遍,也有一些心得体会。所以决定通过博客的方式将其分享出来,算是对这段时间研究 Retrofit 的归纳和总结,同时希望对大家有帮助。

关于 Retrofit 框架的文章预计会有好几篇,文章的特点如下:

  • 文章的组织方式不会一头扎进源码分析一通,而是先从使用案例入手,然后分析其实现原理。

  • Retrofit 是一个网络框架,那么最好是有一个服务端与之对应,这样才能更好的对网络请求进行调试。所以我搭建了一个 Tomcat + Servlet 服务器用来接收网络请求,在调试 Retrofit 框架的时候产生的问题,我将会通过分析源码的方式来解答。

  • 分析源码的一个直接好处是知道其实现原理。除此以外呢?开源框架这么多,我们能不能提取、总结一些通用的东西出来,提高我们的代码水平。我将在本系列文章的最后一篇文章中汇总一下对 Retrofit 源代码分析的体会。

本文基于的 Retrofit2 的版本是 2.7.0

从简单的案例入手

Retrofit 的使用是非常简单的,看一下官方文档基本上就能上手了。所以本文不会介绍 Retrofit 每个注解的使用,如果对 Retrofit 不熟的,可以花几分钟的时间在 retrofit官网 上了解下。

下面我们来看一个简单的案例:

// 定义网络接口类interface UserService {@POST("register")@FormUrlEncodedfun register(@Field("username") username: String,@Field("mobile") mobile: String): Call>}private val userService by lazy {// 构建 Retrofit 实例val retrofit: Retrofit = Retrofit.Builder().baseUrl(API_URL).addConverterFactory(GsonConverterFactory.create()).build()// 创建网络接口的实现类retrofit.create(UserService::class.java)}private fun request() {// 调用业务方法,返回一个 Call 对象val call = userService.register("chiclaim", "110")showLoading()// 执行网络请求call.enqueue(object : retrofit2.Callback> {// 网络请求失败回调override fun onFailure(call: Call>, t: Throwable) {dismissLoading()ToastHelper.showToast(applicationContext, t.message)text_content.text = t.message}// 网络请求成功回调override fun onResponse(call: Call>, response: Response>) {dismissLoading()val repsModel = response.body()val code = response.code()if (code in 200..299) {text_content.text = (repsModel?.message)text_content.append("\n")text_content.append(repsModel?.data.toString())} else {text_content.text = "response code ${response.code()}\n${repsModel?.message}"}}})}

上面的案例非常简单,和官网的介绍大同小异,只不过是自己写了一个简单的后端程序来对接这个请求而已。

但是我们不能仅仅满足于 API 调用,我们还应该去了解其背后的实现原理。下面我将对该案例,抛出几个问题,然后通过分析源码的方式找到问题的答案。

抛出问题

针对上面的案例,我抛出了如下几个问题:

  • 我们只是定义了接口(UserService),并没有定义实现类,Retrofit 如何产生实现类的?

  • 在没有使用 Retrofit 之前,发送网络请求,我们需要自己组装参数,Retrofit 如何通过注解组装请求参数的?

  • ConverterFactory 有什么用?它在哪个环节起作用的?

从源码中找到答案

上面的案例中的 retrofit.create() 方法就是用来创建业务实现类的:

retrofit.create(UserService::class.java)

然后我们看下 create 方法的具体实现:

public  T create(final Class service) {    validateServiceInterface(service);    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },        new InvocationHandler() {          private final Platform platform = Platform.get();          private final Object[] emptyArgs = new Object[0];          @Override public @Nullable Object invoke(Object proxy, Method method,              @Nullable Object[] args) throws Throwable {              // 如果调用的方法是 Object 方法,则普通调用即可            if (method.getDeclaringClass() == Object.class) {              return method.invoke(this, args);            }// 如果调用的方法是 interface default 方法(JDK1.8)            if (platform.isDefaultMethod(method)) {              return platform.invokeDefaultMethod(method, service, proxy, args);            }// 如果调用的是我们定义的业务方法            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);          }        });}

发现它是使用动态代理实现的,所以第一步是要理解动态代理的基本原理。关于动态代理的作用和基本原理,我以前分析代理模式的时候阐述过,需要的可以移步《设计模式 ~ 深入理解代理模式》

所以对于第一个问题:“我们只是定义了接口(UserService),并没有定义实现类,Retrofit 如何产生实现类的?” 就很好回答了,Retrofit 通过动态代理的方式来实现的。

接下来就要分析 Retrofit 动态代理的具体实现了。在调用具体的业务方法的时候,如:

val call = userService.register("chiclaim", "110")

最终会调用到 InvocationHandler.invoke 方法,上面我已经在 invoke 方法中主要逻辑加上了注释说明。核心的代码逻辑就是:

loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

那来看下 loadServiceMethod 方法 :

ServiceMethod<?> loadServiceMethod(Method method) {    ServiceMethod<?> result = serviceMethodCache.get(method);    if (result != null) return result;    synchronized (serviceMethodCache) {      result = serviceMethodCache.get(method);      if (result == null) {        result = ServiceMethod.parseAnnotations(this, method);        serviceMethodCache.put(method, result);      }    }    return result;}

里面主要逻辑是解析方法注解,封装成 ServiceMethod,然后放在 serviceMethodCache 缓存容器中。loadServiceMethod 方法的主要逻辑在 parseAnnotations 方法里:

  static  ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);    Type returnType = method.getGenericReturnType();    if (Utils.hasUnresolvableType(returnType)) {      throw methodError(method,          "Method return type must not include a type variable or wildcard: %s", returnType);    }    if (returnType == void.class) {      throw methodError(method, "Service methods cannot return void.");    }    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);  }

ServiceMethod.parseAnnotations 方法里主要是两个方法:

  • RequestFactory.parseAnnotations
  • HttpServiceMethod.parseAnnotations

我们先来看下 RequestFactory.parseAnnotations 方法:

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {  return new Builder(retrofit, method).build();}  RequestFactory build() {  // 解析方法上的注解,如 @GET、@POST、@Multipart、@FormUrlEncoded  for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);  }  // 省略参数的校验...    int parameterCount = parameterAnnotationsArray.length;  parameterHandlers = new ParameterHandler<?>[parameterCount];  // 将参数注解转化成 ParameterHandler  // 所有的参数注解都有一个类与之对应,并且该类继承了 ParameterHandler  // 这些类都是 ParameterHandler 的内部类  // ParameterHandler 核心方法是 apply,用于将方法上的参数值添加到 RequestBuilder 当中  for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {parameterHandlers[p] =parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);  }  // 省略参数的校验...  return new RequestFactory(this);}

RequestFactory.parseAnnotations 方法主要是将解析接口方法参数注解,封装在 RequestFactory 对象中,然后将其返回。

这样我们就回答了第二个问题:Retrofit 如何通过注解组装请求参数的? 主要是通过 RequestFactory.parseAnnotations 解析方法上的注解。

RequestFactory 主要用于在后面创建 OkHttp 发起请求所需要的 Request 对象,这个后面会分析到。

我们继续来看下 HttpServiceMethod.parseAnnotations 方法:

  static  HttpServiceMethod parseAnnotations(      Retrofit retrofit, Method method, RequestFactory requestFactory) {    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;    boolean continuationWantsResponse = false;    boolean continuationBodyNullable = false;    Annotation[] annotations = method.getAnnotations();    Type adapterType;    if (isKotlinSuspendFunction) {      Type[] parameterTypes = method.getGenericParameterTypes();      Type responseType = Utils.getParameterLowerBound(0,          (ParameterizedType) parameterTypes[parameterTypes.length - 1]);      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {        // Unwrap the actual body type from Response.        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);        continuationWantsResponse = true;      } else {        // 省略注释...      }      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);    } else {      adapterType = method.getGenericReturnType();    }// 创建 CallAdapter,后面会详细分析 CallAdapter 类    CallAdapter callAdapter =        createCallAdapter(retrofit, method, adapterType, annotations);    Type responseType = callAdapter.responseType();    // 省略参数校验...// 创建 responseConverter 用于将请求的返回结果,转换成需要的对象    Converter responseConverter =        createResponseConverter(retrofit, method, responseType);// callFactory 是在 Retrofit.build 的时候默认设置进去的 OkHttpClient,用于执行网络请求    okhttp3.Call.Factory callFactory = retrofit.callFactory;// 如果不是 kotlin suspend 函数    if (!isKotlinSuspendFunction) {      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);    }// 如果是 kotlin suspend 函数,且函数的返回类型是 Response,例如:// suspend fun register(    //        @Field("username") username: String,    //        @Field("mobile") mobile: String): Response// 这里的 register 方法就会本逻辑else if (continuationWantsResponse) {      return (HttpServiceMethod) new SuspendForResponse<>(requestFactory,          callFactory, responseConverter, (CallAdapter>) callAdapter);    }// 其他情况。例如 suspend 函数,返回结果是 Body Data,而不是 Response,例如:    // suspend fun register(    //        @Field("username") username: String,    //        @Field("mobile") mobile: String): Userelse {      return (HttpServiceMethod) new SuspendForBody<>(requestFactory,          callFactory, responseConverter, (CallAdapter>) callAdapter,          continuationBodyNullable);    }  }

这样我们就将 ServiceMethod.parseAnnotations 方法里的:RequestFactory.parseAnnotationsHttpServiceMethod.parseAnnotations 分析完毕了。

由于 loadServiceMethod 的主要逻辑是 ServiceMethod.parseAnnotations,所以 loadServiceMethod 也着分析完毕了。所以接下来就要分析下 invoke 方法:

// 动态代理里的核心逻辑(这里在贴一下)loadServiceMethod(method).invoke(args != null ? args : emptyArgs);abstract class HttpServiceMethod {@Override final @Nullable ReturnT invoke(Object[] args) {Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);}// adapt 方法是一个抽象方法,具体使用哪个子类的实现取决于接口函数的使用方式,我们已经在 HttpServiceMethod.parseAnnotations 分析过了// 如果接口函数不是 kotlin suspend 则使用 CallAdapted 类// 如果是 kotlin suspend 函数返回类型是 Response,则使用 SuspendForResponse 类// 接口函数为其他情况如:kotlin suspend 函数返回类型不是 Response,则使用 SuspendForBody 类// 以上 3 个类都是 HttpServiceMethod 的子类protected abstract @Nullable ReturnT adapt(Call call, Object[] args);}

下面我们就来分析下 HttpServiceMethod 的三个子类:

  • CallAdapted
  • SuspendForResponse
  • SuspendForBody

不管是哪个子类,它们的构造方法都依赖 ResponseConverter、CallAdapter(注意不是 CallAdapted)

所以我们先来分析下 ResponseConverter 的创建过程:

val retrofit = Retrofit.Builder()                .baseUrl(API_URL)                .addConverterFactory(GsonConverterFactory.create())                .build()

我们是通过 addConverterFactory 方法将 GsonConverterFactory 转化器工厂加进去的, GsonConverterFactory 创建的是 GsonResponseBodyConverter :

final class GsonResponseBodyConverter implements Converter {  private final Gson gson;  private final TypeAdapter adapter;  GsonResponseBodyConverter(Gson gson, TypeAdapter adapter) {    this.gson = gson;    this.adapter = adapter;  }  @Override public T convert(ResponseBody value) throws IOException {    JsonReader jsonReader = gson.newJsonReader(value.charStream());    try {      T result = adapter.read(jsonReader);      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {        throw new JsonIOException("JSON document was not fully consumed.");      }      return result;    } finally {      value.close();    }  }}

GsonResponseBodyConverter 简而言之就是将响应体里的数据通过 GSON 转化成我们所需要的对象

然后我们在来看 CallAdapter,实际上 CallAdapter 对象是在 HttpServiceMethod.parseAnnotations 方法创建的:

class HttpServiceMethod {static  HttpServiceMethod parseAnnotations(  Retrofit retrofit, Method method, RequestFactory requestFactory) {// 创建 CallAdapterCallAdapter callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);// 省略其他代码...}// createCallAdapterprivate static  CallAdapter createCallAdapter(  Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {try {  // 调用了 Retrofit.callAdapter  return (CallAdapter) retrofit.callAdapter(returnType, annotations);} catch (RuntimeException e) { // Wide exception range because factories are user code.  throw methodError(method, e, "Unable to create call adapter for %s", returnType);}}}public final class Retrofit {public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {return nextCallAdapter(null, returnType, annotations);}      // 我们再来看下 nextCallAdapterpublic CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,  Annotation[] annotations) {  // 省略参数校验...  // 由于上传传递进来的参数 skipPast 是 null,所以 start 就等于 0int start = callAdapterFactories.indexOf(skipPast) + 1;for (int i = start, count = callAdapterFactories.size(); i < count; i++) {  // 从 callAdapterFactories 工厂集合中获取工厂,并且创建 CallAdapter  CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);  if (adapter != null) {return adapter;  }}// 省略组装错误信息...throw new IllegalArgumentException(builder.toString());}}

callAdapterFactories 工厂集合中获取工厂,并且创建 CallAdapter。但是我们文章开头的案例中并没有添加 CallAdapterFactory,我们只是添加了 ConverterFactory

val retrofit: Retrofit = Retrofit.Builder()            .baseUrl(API_URL)            .addConverterFactory(GsonConverterFactory.create())            .build()

其实是在 build 方法中添加默认的 CallAdapterFactory:

public Retrofit build() {    // 省略其他逻辑...  // 创建 CallAdapter 工厂集合  List callAdapterFactories = new ArrayList<>(this.callAdapterFactories);  // 添加默认的 CallAdapterFactory  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));  return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),  unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);}

我们在来看下 Platform.defaultCallAdapterFactories

class Platform {  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(      @Nullable Executor callbackExecutor) {// 创建 DefaultCallAdapterFactory    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);    return hasJava8Types        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)        : singletonList(executorFactory);  }  }

然后我们看下 DefaultCallAdapterFactory 工厂是怎么创建 CallAdapter 的:

final class DefaultCallAdapterFactory extends CallAdapter.Factory {  private final @Nullable Executor callbackExecutor;  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {    this.callbackExecutor = callbackExecutor;  }  // 创建 CallAdapter  @Override public @Nullable CallAdapter<?, ?> get(      Type returnType, Annotation[] annotations, Retrofit retrofit) {    // 省略参数校验...    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);// 如果接口方法使用了 @SkipCallbackExecutor 注解,则不使用 callbackExecutor    final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)        ? null        : callbackExecutor;// 返回 CallAdapter 匿名内部类对象    return new CallAdapter>() {      @Override public Type responseType() {        return responseType;      }      @Override public Call adapt(Call call) {        return executor == null            ? call            : new ExecutorCallbackCall<>(executor, call);      }    };  }}static final class ExecutorCallbackCall implements Call {// 省略其他逻辑...@Override public void enqueue(final Callback callback) {    // 调用 Call.enenque,真正开始执行任务  // delegate 实际上是 OkHttpCall  delegate.enqueue(new Callback() {@Override public void onResponse(Call call, final Response response) {  // 将成功回调放在 callbackExecutor 中执行  callbackExecutor.execute(() -> {if (delegate.isCanceled()) {  callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));} else {  callback.onResponse(ExecutorCallbackCall.this, response);}  });}@Override public void onFailure(Call call, final Throwable t) {  // 将失败回调放在 callbackExecutor 中执行  callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));}  });}// 省略其他逻辑...}   

至此,怎么创建 AdapterFactory 就搞清楚了。

这个时候可以来介绍 HttpServiceMethod 的三个子类了(CallAdapted、SuspendForResponse、SuspendForBody)

经过上面的分析我们知道,当我们接口方法不是 suspend 方法时,如:

@POST("users/new") fun createUser(@Body user: User): Call

HttpServiceMethod.parseAnnotations 将会返回 CallAdapted

  static final class CallAdapted extends HttpServiceMethod {    private final CallAdapter callAdapter;    // 省略构造方法...    @Override protected ReturnT adapt(Call call, Object[] args) {      return callAdapter.adapt(call);    }  }

发现里面非常简单,就是直接调用 callAdapter.adapt 方法而已。

如果是我们的接口函数是 kotlin suspend 函数,且函数的返回类型是 Response,例如:

suspend fun register(   @Field("username") username: String,   @Field("mobile") mobile: String): Response

HttpServiceMethod.parseAnnotations 将会返回 SuspendForResponse,SuspendForResponse 要比 CallAdapted,稍微复杂一点:

static final class SuspendForResponse extends HttpServiceMethod {private final CallAdapter> callAdapter;// 省略构造方法...@Override protected Object adapt(Call call, Object[] args) {  call = callAdapter.adapt(call);  Continuation> continuation =  (Continuation>) args[args.length - 1];  try {return KotlinExtensions.awaitResponse(call, continuation);  } catch (Exception e) {return KotlinExtensions.suspendAndThrow(e, continuation);  }}}suspend fun  Call.awaitResponse(): Response {  return suspendCancellableCoroutine { continuation ->// 协程取消掉的时候,调用 Call.cancel()    continuation.invokeOnCancellation {      cancel()    }// 调用 Call.enenque,真正开始执行网络请求任务    enqueue(object : Callback {      override fun onResponse(call: Call, response: Response) {// 继续执行相应的协程,将 response 作为最后一个挂起点的返回值        continuation.resume(response)      }      override fun onFailure(call: Call, t: Throwable) {        continuation.resumeWithException(t)      }    })  }}  

如果接口函数是 kotlin suspend 函数,但是函数的返回值不是 Response,如:

suspend fun register(          @Field("username") username: String,          @Field("mobile") mobile: String): User

HttpServiceMethod.parseAnnotations 将会返回 SuspendForBody ,它和 SuspendForResponse 差别在于 SuspendForBody 将 Response.body 作为协程挂起点的返回值:

static final class SuspendForBody extends HttpServiceMethod {    private final CallAdapter> callAdapter;    private final boolean isNullable;// 省略构造方法...    @Override protected Object adapt(Call call, Object[] args) {      call = callAdapter.adapt(call);      Continuation continuation = (Continuation) args[args.length - 1];      try {        return isNullable            ? KotlinExtensions.awaitNullable(call, continuation)            : KotlinExtensions.await(call, continuation);      } catch (Exception e) {        return KotlinExtensions.suspendAndThrow(e, continuation);      }    }}// awaitNullable 方法@JvmName("awaitNullable")suspend fun  Call.await(): T? {  return suspendCancellableCoroutine { continuation ->// 协程取消掉的时候,调用 Call.cancel()    continuation.invokeOnCancellation {      cancel()    }// 调用 Call.enenque,真正开始执行网络请求任务    enqueue(object : Callback {      override fun onResponse(call: Call, response: Response) {        if (response.isSuccessful) {  // 继续执行相应的协程,将 response.body 作为最后一个挂起点的返回值          continuation.resume(response.body())        } else {          continuation.resumeWithException(HttpException(response))        }      }      override fun onFailure(call: Call, t: Throwable) {        continuation.resumeWithException(t)      }    })  }}

不管是 CallAdapted、SuspendForResponse、SuspendForBody,它们的 adapt 方法都依赖 OkHttpCall

@Override final @Nullable ReturnT invoke(Object[] args) {    Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);    return adapt(call, args);}

从名字上可以看出最终的请求是通过 OkHttp 来执行最终的网络请求,我们来看下 OkHttpCall:

final class OkHttpCall implements Call {  // 省略成员变量...    // 由于篇幅原因,只保留同步请求和异步请求...    // 异步请求  @Override public void enqueue(final Callback callback) {    okhttp3.Call call;    Throwable failure;    synchronized (this) {      if (executed) throw new IllegalStateException("Already executed.");      executed = true;      call = rawCall;      failure = creationFailure;      if (call == null && failure == null) {        try {  // 里面的实现相当于 OkHttpClient.newCall          call = rawCall = createRawCall();        } catch (Throwable t) {          throwIfFatal(t);          failure = creationFailure = t;        }      }    }// 省略其他代码...// 通过 OkHttp 发起异步网络请求...    call.enqueue(new okhttp3.Callback() {  // 处理请求结果      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {        Response response;        try {  // 将 OkHttp Response 转化成 Retrofit Response          response = parseResponse(rawResponse);        } catch (Throwable e) {          throwIfFatal(e);          callFailure(e);          return;        }        try {  // 成功回调          callback.onResponse(OkHttpCall.this, response);        } catch (Throwable t) {          throwIfFatal(t);          t.printStackTrace();        }      }  // 处理网络失败情况      @Override public void onFailure(okhttp3.Call call, IOException e) {        callFailure(e);      }      private void callFailure(Throwable e) {        try {  // 失败回调          callback.onFailure(OkHttpCall.this, e);        } catch (Throwable t) {          throwIfFatal(t);          t.printStackTrace();        }      }    });  }  // 同步请求  @Override public Response execute() throws IOException {    okhttp3.Call call;    synchronized (this) {      if (executed) throw new IllegalStateException("Already executed.");      executed = true;      // 省略异常抛出...      call = rawCall;      if (call == null) {        try {  // 里面的实现相当于 OkHttpClient.newCall          call = rawCall = createRawCall();        } catch (IOException | RuntimeException | Error e) {          throwIfFatal(e);          creationFailure = e;          throw e;        }      }    }    if (canceled) {      call.cancel();    }// 将 OkHttp Response 转化成 Retrofit Response    return parseResponse(call.execute());  }  private okhttp3.Call createRawCall() throws IOException {// 这里的 callFactory 默认是 OkHttpClient// requestFactory.create 用于创建 OkHttp 发起网络请求所需要的 Request 对象    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));    if (call == null) {      throw new NullPointerException("Call.Factory returned null.");    }    return call;  }  // 解析 OkHttp Response,将其转化成 Retrofit Response  Response parseResponse(okhttp3.Response rawResponse) throws IOException {    ResponseBody rawBody = rawResponse.body();    // Remove the body's source (the only stateful object) so we can pass the response along.    rawResponse = rawResponse.newBuilder()        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))        .build();    int code = rawResponse.code();// HTTP code 非成功状态    if (code < 200 || code >= 300) {      try {        ResponseBody bufferedBody = Utils.buffer(rawBody);        return Response.error(bufferedBody, rawResponse);      } finally {        rawBody.close();      }    }// https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/204// https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/205// HTTP 204 表示该请求已经成功了,但是客户端客户不需要离开当前页面。默认情况下 204 响应是可缓存的。一个 ETag 标头包含在此类响应中// HTTP 205 表示该请求已经成功了,用来通知客户端重置文档视图// 204、205 Response.body 设置为 null,所以上层需要注意 body 为 null 的情况    if (code == 204 || code == 205) {      rawBody.close();      return Response.success(null, rawResponse);    }    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);    try {  // 这里的 responseConverter 实际上就是 GsonResponseBodyConverter  // 这是在 build Retrofit 对象的时候设置的:  // val retrofit: Retrofit = Retrofit.Builder()      //      .baseUrl(API_URL)      //      .addConverterFactory(GsonConverterFactory.create())      //      .build()  // 将会返回结果转成需要的类型      T body = responseConverter.convert(catchingBody);      return Response.success(body, rawResponse);    } catch (RuntimeException e) {      catchingBody.throwIfCaught();      throw e;    }  }}

介绍完 OkHttpCall ,我们也就能回答第三个问题了:“ConverterFactory 有什么用?它在哪个环节起作用的?”

ConverterFactory 主要用于对象的序列化和反序列化,比如说将请求的对象转成 JSON ,然后传递给服务器,获取将服务器返回的 JSON 转成我们需要的对象。

例如 OkHttpCall.parseResponse 用到的 Converter 将服务器返回的 JSON 转成我们需要的对象。

除此以外,在 OkHttpCall.parseResponse 方法中我们还发现,如果 HTTP code 如果是 204 或者 205,Response 的 body 会是 null,所以在使用的 Retrofit 的时候就一定要注意 body 空的情况。比如:

@POST("register")@FormUrlEncodedfun registerByRxJava(@Field("username") username: String?,@Field("mobile") mobile: String): Observable?>

如果此时 HTTP code 是 204 或 205 ,虽然网络请求成功,但是会抛出空指针异常:

java.lang.NullPointerException: Null is not a valid element

这个我们将在介绍 Retrofit 结合 RxJava 使用的时候继续分析。

小结

至此,我们就以一个简单的案例为引子,将 Retrofit 是如何发起网络请求的整个过程以及 Retrofit 里的一些核心概念如 动态代理、CallAdapter、Converter 等都介绍完毕了。

本文涉及到的代码在我的 AndroidAll GitHub 仓库中。该仓库除了 Retrofit,还有Android 程序员需要掌握的技术栈,如:程序架构、设计模式、性能优化、数据结构算法、Kotlin、Flutter、NDK、Router、RxJava、Glide、LeakCanary、Dagger2、Retrofit、OkHttp、ButterKnife、Router 等等,持续更新,欢迎 star。

更多相关文章

  1. Android使背景灯(Brightness)高亮的方法
  2. 【Android】View绘制过程分析之draw
  3. android spinner自动弹出列表,设置title,TtextView不换行自动截取
  4. [置顶] Android系统安全之旅 第1章 编译Android程序的方法
  5. Android:捕捉触摸屏手势
  6. Android(安卓)的网络编程
  7. Android(安卓)发送短信 和 打电话 具体事项
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. android Service中启动Dialog
  2. Android(安卓)的monkey测试及排错步骤
  3. Android(安卓)超强图片工具类BitmapUtil
  4. Android(安卓)库 Gson
  5. js 急速入门之六(classList,dataset对象,选
  6. Android(安卓)与蓝牙串口通讯
  7. 关于手机的像素
  8. notifying the user/通知用户
  9. android启动一个应用程序大概流程
  10. 计算机图书pdf整理及下载链接