为了账号安全,请及时绑定邮箱和手机立即绑定

Retrofit源码分析

标签:
Android

webp

版本号:2.5.0

一.基本使用

1.定义请求接口

interface GithubService {    //通过注解定义请求的方法以及路径,“{}”里面的表示:该内容是可变的,通过下面方法的参数赋值
    @GET("users/{user}/repos")    fun listRepos(@Path("user") user: String): Call<Any>
}

2.创建Retrofit对象,通过Call对象发送网络请求

//创建Retrofit对象val retrofit = Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())//设置数据解析器
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//设置支持Rxjava平台
        .build()//创建网络请求接口实例val githubService = retrofit.create(GithubService::class.java)
//调用相应的接口获取对应的call对象val call = githubService.listRepos("user")//通过call对象执行异步请求call.enqueue(object : Callback<Any> {    override fun onFailure(call: Call<Any>, t: Throwable) { }    override fun onResponse(call: Call<Any>, response: Response<Any>) {  }
})

通过上面的代码可以看出,真正发送网络请求的是Call对象,也就是OkhttpRetrofit只是对网络请求参数的封装,真正的请求是通过Okhttp完成的。

应用通过Retrofit发送网络请求,实际上是使用Retrofit接口层封装请求参数,之后由Okhttp完成后续的请求操作,在服务端返回数据之后,Okhttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析。

Okhttp源码分析

二.源码分析

1.创建对象

网络请求参数的封装是通过Retrofit完成的,所以先看一下给对象的创建代码:
Retrofit.Builder()

public static final class Builder {    //Retrofit支持平台
    private final Platform platform;    //网路请求的okhttp的工厂,默认就是OkhttpClient
    private @Nullable okhttp3.Call.Factory callFactory;    //请求的基地址
    private @Nullable HttpUrl baseUrl;    //数据转换器工厂集合;数据转换器就是将从网络获取的数据转成java对象
    private final List<Converter.Factory> converterFactories = new ArrayList<>();    //适配器工厂集合;适配器工厂:将我们Call对象转换成其他类型能用的请求,比如:Rxjava
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();    //用于执行异步回调的,在Android是默认在主线程中回调
    private @Nullable Executor callbackExecutor;    //标志位,用于后面是否立即解析方法参数
    private boolean validateEagerly;

    Builder(Platform platform) {      this.platform = platform;
    }    public Builder() {      this(Platform.get());
    }     public Retrofit build() {      if (baseUrl == null) {        throw new IllegalStateException("Base URL required.");
      }      //其他的成员变量判断
      ......      //创建Retrofit对象,该对象中也有对应的成员变量,除了platform
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

}

重点关注一下成员变量,如注释所示。在上述代码中Builder()会调用Builder(Platform platform)传入一个Platform对象,下面看一个该对象创建的代码:Platform.get()

class Platform {    private static final Platform PLATFORM = findPlatform();    static Platform get() {    return PLATFORM;
    }    private static Platform findPlatform() {    try {      //加载指定的类
      Class.forName("android.os.Build");      //如果Build.VERSION.SDK_INT != 0,说明是Android平台
      if (Build.VERSION.SDK_INT != 0) {        return new Android();
      }
    } ......    try {
      Class.forName("java.util.Optional");      return new Java8();
    }......    return new Platform();
}

从上述代码可以看出,Retrofit支持AndroidJava8平台。这里我们只关注Android平台,下面看一下Android中做了什么。

static class Android extends Platform {
    ......    @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 List<? extends Converter.Factory> defaultConverterFactories() {      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }
    ......    static class MainThreadExecutor implements Executor {      private final Handler handler = new Handler(Looper.getMainLooper());      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
}

Android中提供了默认的Executor、ConverterFactor和CallAdapterFactory,其中默认的异步异步回调处理是在AndroidUI线程处理的new Handler(Looper.getMainLooper());,这也就是为什么Retrofit网络请求回调是在主线程中执行的(Okhttp的回调是在子线程中执行的)

2.参数设置

baseUrl()

public Builder baseUrl(String baseUrl) {
     checkNotNull(baseUrl, "baseUrl == null");     //HttpUrl对baseUrl进行解析分段,如获取:scheme、host、port和PathSegments
     return baseUrl(HttpUrl.get(baseUrl));
}public Builder baseUrl(HttpUrl baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    List<String> pathSegments = baseUrl.pathSegments();    //baseUrl的必须以“/”结尾
    if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
    }    this.baseUrl = baseUrl;    return this;
}

注意:baseUrl的必须以“/”结尾,否则抛出异常IllegalArgumentException(baseUrl must end in /:)

addConverterFactory()

public Builder addConverterFactory(Converter.Factory factory) {
    converterFactories.add(checkNotNull(factory, "factory == null"));    return this;
}

该方法很简单,就是把设置的工厂添加到对应的集合中,重点看一下Converter.Factory对象的创建:GsonConverterFactory.create()

public static GsonConverterFactory create() {    return create(new Gson());
}public static GsonConverterFactory create(Gson gson) {    if (gson == null) throw new NullPointerException("gson == null");    return new GsonConverterFactory(gson);
}private GsonConverterFactory(Gson gson) {    this.gson = gson;
}

创建的过程就是创建一个Gson对象,然后给GsonConverterFactory的属性gson赋值。

addCallAdapterFactory()

该方法同addConverterFactory()类似,将Factory对象添加到相应的集合中。RxJava2CallAdapterFactory.create()方法也类似,创建一个RxJavaScheduler对象并赋值。

3.获取请求接口实例

retrofit.create(GithubService::class.java)

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];          //proxy:代理对象
          //method:调用的方法信息
          //args:调用方法的参数
          //当代理对象方法调用的时候就会调用该方法
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {            // 如果调用的是Object类中的方法,比如:toString()方法等
            if (method.getDeclaringClass() == Object.class) {              return method.invoke(this, args);
            }            //如果是平台默认的方法,Android平台该方法返回false,所以if条件不成立。
            if (platform.isDefaultMethod(method)) {              return platform.invokeDefaultMethod(method, service, proxy, args);
            }            //最终会调用该方法
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
}

Android平台下调用请求方法时,是通过动态代理来实现的,在这个过程中最终会调用loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

我们先看一下loadServiceMethod(method)方法

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;
}

loadServiceMethod方法就是返回了一个ServiceMethod对象,该对象是对请求方法method的封装,如果缓存中存在就从缓存中获取,否则直接创建一个:ServiceMethod.parseAnnotations(this, method);ServiceMethod是一个抽象类,调用的是它子类HttpServiceMethodparseAnnotations方法,在该方法中直接new HttpServiceMethod对象,下面就看一下该类中的相关属性和方法:

final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
  ......  //请求工厂,里面封装着请求方法先关的信息
  private final RequestFactory requestFactory;  //请求工厂:其实就是OkhttpClient
  private final okhttp3.Call.Factory callFactory;  private final CallAdapter<ResponseT, ReturnT> callAdapter;  private final Converter<ResponseBody, ResponseT> responseConverter;
  ......  @Override ReturnT invoke(Object[] args) {    return callAdapter.adapt(        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }
}

下面重点看一下RequestFactory

final class 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;
    ......
}

RequestFactory的成员变量可以看出该类中包括请求相关的所有信息。

创建好ServiceMethod对象以后,调用该对象的invoke方法:

@Override ReturnT invoke(Object[] args) {    return callAdapter.adapt(        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}

该方法就会返回一个Call对象,allAdapter.adapt()方法就是将OkHttpCall对象转换成其他平台能用的Call对象,比如:RxJava。这里返回的是OkHttpCall的对象,该类是Retrofit中定义的,是对Okhttp中的Call对象的封装。下面看一下该类中的相关属性和方法:

final class OkHttpCall<T> implements Call<T> {    private final RequestFactory requestFactory;    private final Object[] args;    private final okhttp3.Call.Factory callFactory;    private final Converter<ResponseBody, T> responseConverter;    private volatile boolean canceled;    @GuardedBy("this")    private @Nullable okhttp3.Call rawCall;
    ......    //异步请求方法
    @Override public void enqueue(final Callback<T> 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 {
              call = rawCall = createRawCall();
            }......
          }
        }
        ......        //调用Okhttp-》call的enqueue方法,完成网络请求
        call.enqueue(new okhttp3.Callback() {            @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
                Response<T> response;                try {                  //解析响应数据
                  response = parseResponse(rawResponse);
                }......
                
        }
    }
    ......    //创建Call对象:okHttpClient.newCall(request)
    private okhttp3.Call createRawCall() throws IOException {
        okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
        ......        return call;
    }    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
        ResponseBody rawBody = rawResponse.body();
        rawResponse = rawResponse.newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();        int code = rawResponse.code();        //code判断
        if (code < 200 || code >= 300) {          try {
            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);
        }......
    }
}

OkHttpCallOkhttpCall封装了一下,它里面的enqueue方法其实调用的就Call.enqueue,在它的回调成功方法中,通过配置的Converter.Factory将响应数据转换成对应的实体类(Java对象)。还有一个需要关注的地方就是,Requst的创建,是通过requestFactory.create(args)创建的,下面看一下该方法:

final class RequestFactory {
    ......
    okhttp3.Request create(Object[] args) throws IOException {        @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
        //方法参数解析器,解析接口中定义的方法
        ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;        //调用方法传入的参数
        int argumentCount = args.length;        if (argumentCount != handlers.length) {        throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
        }        //通过Builder模式创建Request对象
        RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
        headers, contentType, hasBody, isFormEncoded, isMultipart);

        List<Object> argumentList = new ArrayList<>(argumentCount);        //设置请求参数
        for (int p = 0; p < argumentCount; p++) {
            argumentList.add(args[p]);
            handlers[p].apply(requestBuilder, args[p]);
        }        return requestBuilder.get()
        .tag(Invocation.class, new Invocation(method, argumentList))
        .build();
    }
    ......
}

该方法就是根据ParameterHandler解析的参数以及传入的参数值args创建Request对象

总结

在调用Retrofitcreate方法获取接口请求实例Call对象,内部使用的是动态代理的方式,在调用相应的网络请求方法的时候,会回调invoke方法,在该方法中会调用ServiceMethod()invoke方法。
ServiceMethod是一个抽象类,实际使用的是HttpServiceMethod,该类是对请求方法信息的封装,里面有几个比较重要的成员变量:

  • 1.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;
  • 2.okhttp3.Call.Factory

  • 3.callAdapter

  • 4.responseConverter



作者:慕涵盛华
链接:https://www.jianshu.com/p/8c6cdf981ae3


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消