手把手debug源码之Retrofit

本文基于Retrofit2.5.0进行源码分析,以发送一个异步get网络请求为例,直到取回数据再渲染到页面的整个过程。Gif示例如下:

Retrofit源码分析首页.gif

本文不过多解释Retrofit是怎样使用的,本文假设你已经使用过它并对其有一定程度的了解,那么你应该清楚它有几个可以自由配置的属性分别是:callFactory、converterFactories、callAdapterFactories、callbackExecutor;掌握这几个属性对于理解Retrofit源码起着关键作用。

callFactory:网络请求器,用于发起真正的网络请求。
converterFactories:数据转换器,用于将网络请求的结果转换成你想要的目标数据结构,比如GsonJacksonSimple XML
callAdapterFactories:网络请求适配器,用于将网络请求包装成不同的类型,如默认的Call、RxJava2的ObservableKotlin的coroutines
callbackExecutor:回调执行器,用于将网络请求的结果从子线程拉回到主线程。

使用Retrofit发送一个网络请求的代码如下所示,你也可以直接下载demo运行。

//step1:创建Retrofit实例
val retrofit = Retrofit.Builder()
        .baseUrl("http://gank.io/api/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()

//step2:创建接口服务类的代理对象,这里是gankService
val gankService = retrofit.create(GankService::class.java)

//step3:访问接口服务类中的具体业务方法,得到一个适配器对象,这里的categoriesCall是Call<ResponseCategory>类型
val categoriesCall = gankService.categories()

//step4:通过categoriesCall发起网络请求,在Callback中解析数据并处理后续业务逻辑。
categoriesCall.enqueue(object : Callback<ResponseCategory> {
    override fun onFailure(call: Call<ResponseCategory>, t: Throwable) {
        Log.e("MainActivity", "访问失败", t)
    }

    override fun onResponse(call: Call<ResponseCategory>, response: Response<ResponseCategory>) {
        val body = response.body()
        body?.takeIf { result -> !result.isError }?.also { category ->
            Toast.makeText(this@MainActivity, "访问成功 -> " + Gson().toJson(category), Toast.LENGTH_SHORT).show()
        }
    }
})

在上面代码中对step1至step4做了详细的注释,这四个步骤基本就是Retrofit发起网络请求的流程。但源码分析还可以继续深究,在step4发起网络请求时,其中的细节还有很多精彩好戏。这里看上去是categoriesCall这个适配器发起网络请求,但它并不具备这个能力,真正发起网络请求的是callFactory这个网络请求器,callFactory作为网络请求适配器中的一个属性,在构造时就被传到了网络请求适配器中,这里的细节后续会结合代码和debug截图再次分析。

当拿到网络请求返回结果后,会将数据给到数据转换器转换成你想要的目标数据结构,这步我们看作是step5,这个步骤发生在OkHttpCall中。

demo中我们发起异步请求,所以目标数据转换成功后,需要将执行线程从子线程切换到主线程,这步我们看作是step6,这个步骤发生在ExecutorCallbackCall中;另外如果发送同步请求时,是没有这一步骤的。

所以利用Retrofit发送一个异步get网络请求,具体流程如下:

step1. 创建Retrofit实例
step2. 创建网络请求接口服务类的代理对象
step3. 通过代理对象访问接口服务类中的具体业务方法
step4. 通过网络请求结果适配器发起网络请求
step5. 通过数据转换器转成目标数据结构
step6. 通过回调器将代码执行从子线程拉回到主线程

step1. 创建Retrofit实例

下面的代码是最简洁的创建Retrofit实例的代码,这里只配置了数据转换器,其余没有配置的属性,如callFactory、callAdapterFactories、callbackExecutor都采用默认的,接下来会详细分析。

val retrofit = Retrofit.Builder()
        .baseUrl("http://gank.io/api/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()

首先这里通过外观模式,提供了一个统一的接口(Retrofit)用来访问子系统中的一群接口。然后通过建造者模式,配置了baseUrl以及ConverterFactory。建造者模式将Retrofit这个对象的构造过程抽象了出来,开发者可以灵活的组合和配置这几个属性。如若不采用这种方式,Retrofit务必要提供多种重载的构造函数来满足不同开发者的需求,现在通过这种设计模式,直接将这个问题抛给了开发者,开发者要用哪个则配置哪个。

在Retrofit.Buildre()的源码中,有如下构造函数:

public Builder() {
    this(Platform.get());
}

这里需要重点分析下Platform这个类,这个类描述了Retrofit当前处于哪个平台,以及callFactory等属性的默认实现。在2.5.0版本的源码中区分三个平台:Android、Java8以及默认的Platform。源码如下所示:

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        //Android平台
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      //Java8平台
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    //默认平台
    return new Platform();
  }
  ...
}

我们重点分析Android平台下的表现,源码如下所示,defaultCallbackExecutor()中返回了MainThreadExecutor的实例对象,里面创建了一个基于主线程looper的handler对象;defaultCallAdapterFactories()中创建了ExecutorCallAdapterFactory的实例对象,它是Android平台默认的网络请求结果适配器工厂;defaultConverterFactories()中在SDK24及以上的版本创建了OptionalConverterFactory的实例对象,在24以下是EmptyList的实例。

static class Android extends Platform {
  @IgnoreJRERequirement // Guarded by API check.
  @Override boolean isDefaultMethod(Method method) {
    if (Build.VERSION.SDK_INT < 24) {
      return false;
    }
    return method.isDefault();
  }

  //默认回调执行器
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }

  //默认网络请求结果适配器的工厂列表
  @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
    return Build.VERSION.SDK_INT >= 24
      ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
      : singletonList(executorFactory);
  }

  @Override int defaultCallAdapterFactoriesSize() {
    return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
  }

  //默认数据转换器的工厂列表
  @Override List<? extends Converter.Factory> defaultConverterFactories() {
    return Build.VERSION.SDK_INT >= 24
        ? singletonList(OptionalConverterFactory.INSTANCE)
        : Collections.<Converter.Factory>emptyList();
  }

  @Override int defaultConverterFactoriesSize() {
    return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
  }

  static class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());

    @Override public void execute(Runnable r) {
      handler.post(r);
    }
  }
}

这里可以看到网络请求结果适配器和数据转换器都采用了工厂模式,你只要将工厂配置进来,至于怎么创建对象,则不需要你过多关心,只需要知道调用create()就可以。

我们回到代码主线分支,在执行到Retrofit.Buildre().build()时,就会将刚才基于Andorid平台各个属性的默认配置传入到Retrofit的构造函数中,最后通过new关键字创建好Retrofit实例对象,源码如下:

//build源码
public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }

  //网络执行器,demo中没有设置,故采用默认的OkHttpClient
  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

  //回调执行器,这里用到了装饰者模式,这里本来想要一个普通的Executor
  //然后返回了一个带有线程切换功能的Executor,动态地将责任附加到callbackExecutor上
  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  //网络请求结果适配器
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

  //数据转换器
  List<Converter.Factory> converterFactories = new ArrayList<>(
      1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

  converterFactories.add(new BuiltInConverters());
  converterFactories.addAll(this.converterFactories);
  converterFactories.addAll(platform.defaultConverterFactories());

  //构造Retrofit实例对象
  return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

总结:在这一步中,通过建造者模式,灵活配置所需的各个属性(网络请求器、数据转换器、网络请求结果适配器、回调执行器),最后通过new关键字创建Retrofit的实例对象。遇到没有配置的属性,则通过Platform找到对应的平台,然后再找到该平台下的各个属性的默认配置,最后将属性值递到Retrofit的构造函数中。数据转换器和网络请求结果适配器还采取了工厂模式,隐藏具体的创建细节,让具体工厂自己创建其对象。

step2. 创建网络请求接口的代理对象

通过Retrofit实例创建代理对象的源码如下所示,传入参数是网络请求服务接口的Class对象(即GankService),返回的是该接口的代理对象。

val gankService = retrofit.create(GankService::class.java)

在2.5.0版本的Retrofit源码中,create的源码如下所示,因为我们没有设置validateEagerly的值,所以它默认false,然后就是通过Proxy.newProxyInstance创建代理对象。

public <T> T create(final Class<T> 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();
      private final Object[] emptyArgs = new Object[0];

      @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);
        }
        return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
      }
    });
}

newProxyInstance方法中的第一个参数service.getClassLoader()得到类加载器是PathClassLoader,它是Android系统默认的类加载器 (另外DexClassLoader与PathClassLoader的区别感兴趣的童鞋可以自行查阅资料) ;第二个参数是GankService接口的Class对象,这个数组表明要代理哪些接口;第三个参数是动态代理对象,就是外部调用GankService的业务方法时,实际上会被代理回调到这里,然后在invoke方法里面准备网络请求所必须的全部实例对象,如:callAdapter选哪个,responseConverter选哪个等。下面截图是debug create方法的标注说明:

Retrofit-create.jpg

总结:在这一步中,Retrofit通过代理模式创建代理对象,当你在外部调用业务方法时会进行拦截,然后进入到InvocationHandler的invoke方法中控制程序的执行逻辑和流程。

step3. 通过代理对象访问接口服务类中的具体业务方法

前面两步分别创建了Retrofit实例,然后通过该实例创建了网络请求接口的代理对象,接下来就是通过代理对象访问接口服务类中的具体业务方法,对应如下代码:

val categoriesCall = gankService.fetchCategories()

下面截图是debug gankService.fetchCategories方法的标注说明:

ganService.fetchCategories.jpg

通过上面截图可以看到调用gankService.fetchCategories()后,程序流程来到了InvocationHandler的invoke方法中,这里主要分析这句:return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);。这里分三步走,第一步:loadServiceMethod(method);第二步:invoke(args != null ? args : emptyArgs);第三步:return。

loadServiceMethod(method)

loadServiceMethod顾名思义就是将加载fetchCategories()这个method对象,这个方法会返回一个ServiceMethod类型的实例,实际上是返回HttpServiceMethod类型。下面是loadServiceMethod的源码,可以看到进入该方法,会先从serviceMethodCache缓存中去取(这里用到单例模式思想),没有的话就上锁然后解析method的注解。

ServiceMethod<?> loadServiceMethod(Method method) {
  //先取缓存
  ServiceMethod<?> result = serviceMethodCache.get(method);
  if (result != null) return result;

  //上锁
  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
      //解析method对象的注解
      result = ServiceMethod.parseAnnotations(this, method);
      //存入缓存
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}

下面我们重点分析ServiceMethod是怎样解析method对象的注解的。进入到ServiceMethod.parseAnnotations,源码如下:

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  //RequestFactory描述了一个网络请求所需的全部属性
  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.");
  }

  //将retrofit实例、method实例以及requestFactory实例传到HttpServiceMethod中去解析
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

可以看到第一行通过RequestFactory去解析注解,得到一个RequestFactory实例对象,这个对象非常重要,它包含了网络请求的所有必要数据,我们可以将其看作是一个网络请求的对象描述。RequestFactory解析源码如下,这里并不是完整源码,只截取关键部分用于说明流程,下面的代码都在必要处添加了注释。

//RequestFactory中的所有属性
private final Method method;
private final HttpUrl baseUrl;
final String httpMethod;
private final @Nullable String relativeUrl;
private final @Nullable Headers headers;
private final @Nullable MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
  //用建造者模式按需拼装各个属性
  return new Builder(retrofit, method).build();
}

//Builder类的构造函数,保存method和methodAnnotations以及参数信息
Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}

//build方法关键代码
RequestFactory build() {
  //循环解析methodAnnotations
  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }
}

//解析方法体注解的关键源码
private void parseMethodAnnotation(Annotation annotation) {
  if (annotation instanceof DELETE) {
    parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
  } else if (annotation instanceof GET) {
    parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
  } else if (annotation instanceof HEAD) {
    parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
  } else if (annotation instanceof PATCH) {
    parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
  } else if (annotation instanceof POST) {
    parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
  } else if (annotation instanceof PUT) {
    parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
  } else if (annotation instanceof OPTIONS) {
    parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
  } else if (annotation instanceof HTTP) {
    HTTP http = (HTTP) annotation;
    parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
  } else if (annotation instanceof retrofit2.http.Headers) {
    ...
  } else if (annotation instanceof Multipart) {
    ...
  } else if (annotation instanceof FormUrlEncoded) {
    ...
  }
}

//解析参数的关键代码,里面再通过parseParameter解析每个注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
  parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
}

//build方法的最后一句构造了一个描述网络请求的工厂
return new RequestFactory(this);

下面截图是debug RequestFactory.parseAnnotations方法的标注说明:

RequestFactory.parseAnnotations.jpg

小结下这一步,RequestFactory通过其自身的静态方法parseAnnotations解析出method对象上的所有注解,最终通过 new RequestFactory(this); 构造出一个描述网络请求的工厂并将其返回。至此我们拿到了描述一个网络请求的工厂,接着ServiceMethod的parseAnnotations往下看,程序会执行 HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); 这一句,其源码如下所示:

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
  //网络请求适配器
  CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
  Type responseType = callAdapter.responseType();
  if (responseType == Response.class || responseType == okhttp3.Response.class) {
    throw methodError(method, "'"
        + Utils.getRawType(responseType).getName()
        + "' is not a valid response body type. Did you mean ResponseBody?");
  }
  if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
    throw methodError(method, "HEAD method must use Void as response type.");
  }

  //数据转换器
  Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);

  //okhttp3.Call.Factory,这里就是OkHttpClient
  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  
  return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}

首先会创建网络请求适配器,接着创建数据转换器,再获取之前配好的okhttp3.Call.Factory以及上文创建的requestFactory,最后一并传入到HttpServiceMethod的构造函数中。经过这么多的步骤,我们发现到这里其实全在准备Retrofit所需的各个零部件,不过也算是全部准备就绪。此时我们会得到一个HttpServiceMethod,该对象包含了发送网络请求的所有必要零部件,下面截图是debug HttpServiceMethod.parseAnnotations方法的标注说明:

HttpServiceMethod.parseAnnotations.jpg

这里以创建网络请求适配器为例说明Retrofit中是怎样选择合适的适配器的,另外选择数据转换器的逻辑差不多,故不再细述。createCallAdapter源码如下所示:

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(Retrofit retrofit, Method method) {
  //得到返回值类型
  Type returnType = method.getGenericReturnType();
  
  //得到所有注解
  Annotation[] annotations = method.getAnnotations();
  
  try {
    //noinspection unchecked
    return (CallAdapter<ResponseT, ReturnT>) 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);
  }
}

先通过method对象拿到返回值类型和注解数组,再通过retrofit实例对象的callAdapter,传入返回值类型和注解,来寻找合适的CallAdapter,这里其实用到了策略模式,根据不同的返回值类型拿到不同的callAdapter就是一种策略选择,retrofit.callAdapter的源码如下所示:

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
  return nextCallAdapter(null, returnType, annotations);
}

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,Annotation[] annotations) {
  int start = callAdapterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      return adapter;
    }
  }
  ...
}

可以看到其实就是在callAdapterFactories这个集合对象中寻找一个跟返回值类型匹配的callAdapter。因为我们处于Android平台上,又是默认的callAdapter,所以callAdapterFactories.get(i)这里得到的实际就是ExecutorCallAdapterFactory,再调用里面的get方法得到一个类型匹配的CallAdapter,这个网络请求结果适配器能发起真正的网络请求。这里得到的是默认的网络请求结果适配器:ExecutorCallbackCall。源码如下所示:

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        //默认的网络请求结果适配器
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
  ...
}

小结下这里就是创建了HttpServiceMethod实例对象,这个实例对象包含了网络请求适配器,数据转换器,okhttp3.Call.Factory以及网络请求工厂requestFactory。

invoke(args != null ? args : emptyArgs)

为了更好的说明调用流程,下面截图是debug Retrofit的create方法中的invoke方法的标注说明:


Retrofit.create.invoke.jpg

这里其实调用了上面HttpServiceMethod实例对象的invoke方法,源码如下所示,首先会创建OkHttpCall的实例对象,OkHttpCall实现了Retrofit的Call接口,Call接口描述的是发起网络请求的功能,包括同步和异步两种方式。所以这里的OkHttpCall并不是真正的okhttp3.Call,只是Retrofit对网络请求功能的一种包装。

//HttpServiceMethod的invoke方法
@Override ReturnT invoke(Object[] args) {
  //就是上面的ExecutorCallbackCall
  return callAdapter.adapt(
      new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}

//OkHttpCall实现了Call
final class OkHttpCall<T> implements Call<T> {
  ...

  OkHttpCall(RequestFactory requestFactory, Object[] args,
    okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) {
    this.requestFactory = requestFactory;
    this.args = args;
    this.callFactory = callFactory;
    this.responseConverter = responseConverter;
  }

  ...
}

//Retrofit中的Call接口,描述了网络请求的功能
public interface Call<T> extends Cloneable {

  ...

  //同步执行
  Response<T> execute() throws IOException;

  //异步执行
  void enqueue(Callback<T> callback);

  //网络请求
  Request request();

  ...
}

总结:在这一步中,外部通过代理对象访问接口服务类中的具体业务方法,即:gankService.fetchCategories()。此时会被代理对象的InvocationHandler拦截执行它里面的invoke方法,该方法会得到一个HttpServiceMethod实例对象,并调用它自身的invoke方法;进入HttpServiceMethod中的invoke方法后,接下来的流程便会转入到callAdapter,实际会转入到ExecutorCallAdapterFactory的adapt中,最终会返回一个带有回调功能的适配器。这个跟我们在GankService中定义的业务方法fetchCategories返回值类型一致:Call<ResponseCategory>,不过Call的实际类型是ExecutorCallbackCall而已。

step4. 通过适配器发起网络请求

终于拿到了网络请求结果适配器,此时可以发起同步或者异步的网络请求了,demo中发起了异步请求,所以这里分析异步流程,同步请求流程可自行debug调试。

categoriesCall.enqueue(object : Callback<ResponseCategory> {
    override fun onFailure(call: Call<ResponseCategory>, t: Throwable) {
        Log.e("MainActivity", "访问失败", t)
    }

    override fun onResponse(call: Call<ResponseCategory>, response: Response<ResponseCategory>) {
        val body = response.body()
        body?.takeIf { result -> !result.isError }?.also { category ->
            Toast.makeText(this@MainActivity, "访问成功 -> " + Gson().toJson(category), Toast.LENGTH_SHORT).show()
        }
    }
})

上文中提到过categoriesCall的实际类型是ExecutorCallbackCall,下面是ExecutorCallbackCall的部分源码,在enqueue()中执行delegate.enqueue,这里的delegate的实际类型是OkHttpCall,所以实际上执行了OkHttpCall里面的enqueue方法。

static final class ExecutorCallbackCall<T> implements Call<T> {
  final Executor callbackExecutor;//回调执行器
  final Call<T> delegate;//实际类型是OkHttpCall

  ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
    this.callbackExecutor = callbackExecutor;
    this.delegate = delegate;
  }

  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");

    //实际执行的是OkHttpCall的enqueue()
    delegate.enqueue(new Callback<T>() {
      @Override public void onResponse(Call<T> call, final Response<T> response) {
        //回调执行器将运行流程从子线程拉到主线程
        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 {
              //成功时的回调,此时response就是目标数据结构,将这份数据传回到业务调用发起的地方
              callback.onResponse(ExecutorCallbackCall.this, response);
            }
          }
        });
      }

      @Override public void onFailure(Call<T> call, final Throwable t) {
        callbackExecutor.execute(new Runnable() {
          @Override public void run() {
            //失败时回调
            callback.onFailure(ExecutorCallbackCall.this, t);
          }
        });
      }
    });
  }
  ...
}

下面debug截图也验证了delegate的类型:

ExecutorCallAdapterFactory.delegate.enqueue.jpg

下面是OkHttpCall中的enqueue方法源码,终于要发起网络请求了,在这个方法里面定义了okhttp3.Call类型的call,然后通过createRawCall方法创建了真正的网络请求执行器,后面再通过call.enqueue发起了真正的网络请求。一路分析下来,终于发起了真正的网络请求,开不开心,激不激动...

@Override public void enqueue(final Callback<T> callback) {
  
  //主要类型是okhttp3.Call
  okhttp3.Call call;

  synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true;

    call = rawCall;
    failure = creationFailure;
    if (call == null && failure == null) {
      try {
        //创建okhttp3.Call类型的原始Call对象,这个对象才真正具备发送网络请求的能力
        call = rawCall = createRawCall();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

  //通过call对象发起异步网络请求
  call.enqueue(new okhttp3.Callback() {
    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
      Response<T> response;
      try {
        //解析网络请求的结果数据
        response = parseResponse(rawResponse);
      } catch (Throwable e) {
        throwIfFatal(e);
        callFailure(e);
        return;
      }

      try {
        //通过callback回调到ExecutorCallbackCall中
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  });
}

这一步的流程基本分析结束,接下来分析okhttp3.Call的实例对象是如何创建的,我们看下createRawCall方法的源码:

private okhttp3.Call createRawCall() throws IOException {
  //通过callFactory的newCall(),传入requestFactory所描述的一个网络请求所需的必要属性,创建了okhttp3.Call的实例对象。
  //这里callFactory的实际类型是OkHttpClient。
  okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

requestFactory.create(args)这里会创建一个okhttp3.Request,requestFactory描述了一个网络请求所需的完整信息。而callFactory实际上是okhttp3.Call.Factory类型,在创建Retrofit实例的时候就配置好了,实际上就是OkHttpClient的实例对象。这里通过OkHttpClient和okhttp3.Request创建了一个okhttp3.Call。下面截图展示了okhttp3.Call的组成部分:

createRawCall.jpg

总结:在这一步中,外部通过网络请求结果适配器发起异步的网络请求 (categoriesCall.enqueue()),实际执行流程是:ExecutorCallbackCall的enqueue -> OkHttpCall的enqueue -> okhttp3.Call的call调用enqueue。

step5. 通过数据转换器转成目标数据结构

在上面的代码片段中,在call.enqueue里面拿到请求结果后,会调用 parseResponse(rawResponse); 解析rawResponse为目标数据结构,源码如下:

Response<T> 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();
  if (code < 200 || code >= 300) {
    try {
      // Buffer the entire body to avoid future I/O.
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      return Response.error(bufferedBody, rawResponse);
    } finally {
      rawBody.close();
    }
  }

  if (code == 204 || code == 205) {
    rawBody.close();
    return Response.success(null, rawResponse);
  }

  ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
  try {
    //真正转换数据的地方
    T body = responseConverter.convert(catchingBody);
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
    catchingBody.throwIfCaught();
    throw e;
  }
}

关键一句是 T body = responseConverter.convert(catchingBody); 将rawBody转成了目标T,responseConverter是创建OkHttpCall时就传入进来的。下面debug截图展示了response中存放的目标数据结构就是我定义的ResponseCategory类型。

OkHttpCall.enqueue.parseResponse.jpg

step6. 通过回调器将代码执行从子线程拉回到主线程

在得到目标数据结构之后,在OkHttpCall的enqueue中会通过如下回调函数将结果传到ExcutorCallback中。

try {
  //这里的callback实例是在ExecutorCallbackCall中通过new Callback()传进去的,所以回调时回到ExcutorCallback中
  callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
  t.printStackTrace();
}

在ExcutorCallback类中,会通过callbackExecutor对象将结果回调到主线程中,这里的callbackExecutor实际上就是step1中提到的MainThreadExecutor的实例对象,这样就回到了主线程中,然后再执行接下来的业务方法,demo中就是将结果展示了一下。源码如下所示:

//实际执行的是OkHttpCall的enqueue()
delegate.enqueue(new Callback<T>() {
  @Override public void onResponse(Call<T> call, final Response<T> response) {
    //回调执行器将运行流程从子线程拉到主线程
    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 {
          //成功时的回调,此时response就是目标数据结构,将这份数据传回到业务调用发起的地方
          callback.onResponse(ExecutorCallbackCall.this, response);
        }
      }
    });
  }

  @Override public void onFailure(Call<T> call, final Throwable t) {
    callbackExecutor.execute(new Runnable() {
      @Override public void run() {
        //失败时回调
        callback.onFailure(ExecutorCallbackCall.this, t);
      }
    });
  }
});

下面debug截图是callback调用onResponse方法回到业务代码中的标示说明:

callack.onResponse.jpg

总结:在这一步中,主要是通过MainThreadExecutor将结果从子线程拉回到主线程,再接着执行后面的业务逻辑。

一点感想

为了便于自己有个完整的影响,画了一张Retrofit发送一个网络请求流程中所涉及的类的说明图:

Retrofit发送一个网络请求流程中所涉及的类.png

Retrofit本质上是遵循了RESTful风格、通过大量的设计模式封装OkHttp的HTTP网络请求框架,使用起来简洁而优雅。Retrofit将Http请求抽象成Java接口,在接口里用注解描述和配置网络请求参数,用动态代理的方式进行拦截,动态将网络请求接口的注解解析成HTTP请求,最后执行HTTP请求。

Retrofit框架通过大量的设计模式使得代码高度内聚,少量耦合,灵活又轻巧,或许这是每位coder都该追求的一种境界。Retrofit中用到的设计模式有:外观模式代理模式策略模式单例模式思想建造者模式工厂方法模式装饰模式。所以想学习设计模式的你一定不能错过它。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351