一张图带你走进Retrofit源码世界

前提

只有了解了框架的原理才能更好的使用她,才能定位问题的根本。写这篇文章的也是为了自我的学习和提升。其实看源码就跟看书一样,看了这么多本书有什么用呢,其实不然,这些知识已经潜移默化的影响了你的思维。你之后在阅读源码时,会发现能更快的上手了。

引用别人的一句话:当我还是个孩子时吃的很多食物,大部分已经一去不复返而且被我忘掉了,但可以肯定的是,它们中的一部分已经长成我的骨头和肉

友情提醒

1.这篇文章主要讲retrofit如何request 和 response
2.不会详细到每个api
3.文章会以一个flow 来讲解

上图

如果下图有错误欢迎评论指正,如果看不清你可以下载下来放大看,应该会好点。我们这次会以这个图的flow 来讲解(主要是左半边)。

retrofit_flow.png

retrofit初始化配置

这里讲解的就是上图中的adapterFactories,咱们这边以RxjavaAdapter来讲解,下面是一些retrofit的初始化配置。

 private Retrofit createRetrofit(OkHttpClient client, String url) {
        return new Retrofit.Builder()
                .baseUrl(url)
                .client(client)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

这里我们只说一下主要的东西,大家都知道retrofit的adapter 我们根据我们api请求的不同设置不同的adapter来让retrofit执行不同的操作,当我们在设置他的CallAdapter时,点进源码可以看到,retrofit把这个CallAdapter存入了一个集合中

final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();

然后通过build把这个集合回传给了retrofit的这个全局边变量List<CallAdapter.Factory> adapterFactories保存着这些CallAdapter,仔细看的同学会发现,retrofit会默认给你添加一个CallAdapter

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

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      
      //这里就是默认的adapter 防止用户未设置。
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }

以上就说到这里,知道有个CallAdapterFactory集合存在Retrofit的全局变量中。

配置Api

这里讲解的是图中的这方法create(final Class<T> service)稍微提一下吧。上面的adapter其实是根据你在Api中配置的返回参数有关。当我们要使用Rxjava时我们传对应的Rxjava的adapter 如果我们配置的是okhttp的Call回调,自然我们都不需要配置adapter,retrofit都给我们默认配置好了,下图可以看到两种不同的response

public interface Api {

    @Multipart
    @POST("upload")
    Observable<BaseBean> postVoice(@Part("deviceNo") RequestBody deviceNo,
                                   @Part("duration") RequestBody duration,
                                   @Part("title") RequestBody title,
                                   @Part MultipartBody.Part file);
    @GET("selfList")
    Call<VoiceList> getVoiceList(@Query("deviceNo")String deviceNo);

}

Request

这里讲解的是上图中的
create(final Class<T> service)ServiceMethod

当我们要发起请求的时候,我们是不是这样做,拿到之前配置好的Retrofit然后调用他的Create方法然后把相应的api传入.
Retroift.create(Api.class)这样的操作

现在我们进入源码查看这个retrofit最亮点的地方(create(api.class)),通过反射实例化接口,然后拦截接口中的方法,来做api的请求。返回给这个method。

先把源码晾上然后讲解

 public <T> T create(final Class<T> service) {
                ·······省略的代码·······
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
                   ·······省略的代码·······
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

上面的代码已经是把无关紧要的代码剔除了,我们只看重要的代码

  • 我们可以看到create这个方法通过代理反射实例化我们传进来的api接口
  • 然后通过ServiceMethodOkHttpCall来拿到这个方法的相关参数,来invoke这个方法
  • 最后通过serviceMethod.callAdapter.adapt(okHttpCall)把请求到的值返回回去

其实在最后一步大家应该明白了,请求是来自于ServiceMethod的callAdapter参数,然后通过adapt来进行okhttp请求。

下面我会讲解这个calladapter 如何而来。

ServiceMethod如何发起请求

这是一个流程哈,我们这时候进入代码core部分,他的ServiceMethod时通过retrofit的loadServiceMethod拿到的实例化对象。我们进入这个方法可以看到其实这是一个全局的ServiceMethod的cacheMap

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

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

但是不论他做不做缓存肯定有new 的地方,然后才能加入缓存中吧。从上图代码中我们可以看到这个new 的地方。

if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }

这下清楚了ServiceMethod哪里来的了吧,通过new ServiceMethod.Builder<>(this, method).build()这句话来的。看源码不都这样吗!一步一步的进入源码然后理解他的每一层 意思和目的。to be continue

上ServiceMethod.Builder的源码,我们只看重要的代码,其他的忽略

 Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      ·······省略的代码·······
      }

小伙子们,是不是看到了我们一直最关心的calladapter了,在build的时候通过createCallAdapter来初始化了这个值。进入方法看个究竟

private CallAdapter<T, R> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      ·······省略的代码·······
      Annotation[] annotations = method.getAnnotations();
      try {
        ····敲黑板,敲黑板,敲黑板·····
        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);
      }
    }

看到了吧,小伙伴这个calladapter 来自于retrofit里面的方法,我们在loadServiceMethod的时候还记得这句代码吗?new ServiceMethod.Builder<>(this, method).build()我们把retrofit传了进来,然后这里通过retrofit的callAdapter来获取ServiceMethod的adapter。下面是retrofit的源码获取c

 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 = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

  ·······省略的代码·······
  }
  

我感觉只要不眼瞎都能看到这个serviceMethod的calladapter 是来自于我们retrofit之前进行初始化配置时候的RxJavaCallAdapterFactory.create()
其实我们可以在之前的图中看到这个flow,.addCallAdapterFactory(RxJavaCallAdapterFactory.create())最终指向的是ServiceMethod的CallAdapter。

进入RxJavaCallAdapterFactory的源码吧。其实这里的代码并不多,只不过有些杂乱。下面我会把不需要的代码过滤

public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJavaCallAdapterFactory create() {
    return new RxJavaCallAdapterFactory(null, false);
  }

  /**
   * Returns an instance which creates asynchronous observables. Applying
   * {@link Observable#subscribeOn} has no effect on stream types created by this factory.
   */
  public static RxJavaCallAdapterFactory createAsync() {
    return new RxJavaCallAdapterFactory(null, true);
  }

  /**
   * Returns an instance which creates synchronous observables that
   * {@linkplain Observable#subscribeOn(Scheduler) subscribe on} {@code scheduler} by default.
   */
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static RxJavaCallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJavaCallAdapterFactory(scheduler, false);
  }

  private final @Nullable Scheduler scheduler;
  private final boolean isAsync;

  private RxJavaCallAdapterFactory(@Nullable Scheduler scheduler, boolean isAsync) {
    this.scheduler = scheduler;
    this.isAsync = isAsync;
  }

@Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
   ·······省略的代码·······

    if (isCompletable) {
      return new RxJavaCallAdapter(Void.class, scheduler, isAsync, false, true, false, true);
    }

   ·······省略的代码·······

    return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
        false);
  }
}

可以看到这个RxJavaCallAdapterFactory继承了CallAdapter.Factory,实现了他的get方法,在get方法中我们就可以拿到这个CallAdapter,然后进行我们的adapt方法请求。
从上面的代码可以看到真正实现CallAdapter的是
RxJavaCallAdapter 我们继续看看这个RxJavaCallAdapter到底干了什么!!!同样我会过滤不需要的代码

final class RxJavaCallAdapter<R> implements CallAdapter<R, Object> {
·······省略的代码·······

   @Override public Object adapt(Call<R> call) {
    OnSubscribe<Response<R>> callFunc = isAsync
        ? new CallEnqueueOnSubscribe<>(call)
        : new CallExecuteOnSubscribe<>(call);

    OnSubscribe<?> func;
    if (isResult) {
      func = new ResultOnSubscribe<>(callFunc);
    } else if (isBody) {
      func = new BodyOnSubscribe<>(callFunc);
    } else {
      func = callFunc;
    }
    Observable<?> observable = Observable.create(func);

   ·······省略的代码·······
   
    return observable;
  }
}

好了,这下清晰了许多
_这个RxJavaCallAdapter实现了CallAdapter的adapt请求。然后在adapt中需要传入参数就是Call 然而我们可以回到图中看到,OkHttpCall正好是Call的实现类。这里就是上图中的右边部分。_
可以在这个方法中看到了,同步异步请求对应的不一样的然后调用不同的CallEnqueueOnSubscribe,CallExecuteOnSubscribe进行request
进入CallEnqueueOnSubscribe源码看看

final class CallEnqueueOnSubscribe<T> implements OnSubscribe<Response<T>> {
  private final Call<T> originalCall;

  CallEnqueueOnSubscribe(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @Override public void call(Subscriber<? super Response<T>> subscriber) {
    // Since Call is a one-shot type, clone it for each new subscriber.
    Call<T> call = originalCall.clone();
    final CallArbiter<T> arbiter = new CallArbiter<>(call, subscriber);
    subscriber.add(arbiter);
    subscriber.setProducer(arbiter);

    call.enqueue(new Callback<T>() {
      @Override public void onResponse(Call<T> call, Response<T> response) {
        arbiter.emitResponse(response);
      }

      @Override public void onFailure(Call<T> call, Throwable t) {
        Exceptions.throwIfFatal(t);
        arbiter.emitError(t);
      }
    });
  }
}

看到了吧这里终于发起请求了可以看到,执行了OkHttpCall.enqueue请求,同时通过arbiter.emitResponse(response);把参数回调了回来。

这就是retrofit的请求flow。

思路整理

  1. 配置retrofit(addCallAdapterFactory)
  2. 创建ApiService
  3. 通过retrofit的create实例化ApiService接口
  4. 创建ServiceMethod
  5. 通过retrofit的AdapterFactories拿到ServiceMethod的CallAdapter
  6. 创建OkHttpCall请求工具类
  7. 通过ServiceMethod的CallAdapter的adapt进行请求并把第六步写好的call当参数传给adapt。
  8. 把ServiceMethod请求回来的参数返回给对应的ApiService里面的方法
  9. 请求完成

ending

嘿嘿嘿,小伙伴们上面有什么错误的话或者不懂得都可以在留言中提及了,小编会在看到的第一时间响应。

To Be Continued

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

推荐阅读更多精彩内容