源码解析Retrofit

1.Retrofit创建过程

首先 创建一个Retrofit 代码如下:

    fun ProvidesRetrofit(okHttpClient: OkHttpClient): Retrofit {
        var builder = Retrofit.Builder()
                //设置baseUrl
                .baseUrl(ApiService.BASE_URL)
                 //添加一个返回的数据支持转换为Gson对象,其最终会返回配置好的Retrofit类
                .addConverterFactory(GsonConverterFactory.create())
                 //rxjava2的Call进行转化的对象  
                 // .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //当你使用RxJava的时候要添加这个
                 //设置OkHttpClient
                .client(okHttpClient)
        return builder.build()
    }

retrofit是通过建造者模式构建出来的。接下来看Builder方法:

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

查看Platform.get()

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

最终调用了findPlatform()方法,根据不同的运行平台提供不用的线程池。

接下来看build方法:

public Retrofit build() {
     //baseUrl 必须不为空,否则就包异常了
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
     //this.callFactory是我们构建Retrofit时调用了client方法传进来的
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
          //如果没有设置callFactory则直接创建OkHttpClient
        callFactory = new OkHttpClient();
      }

      //callbackExecutor 用来回调传递到UI线程
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      //adapterFactories 主要用于存储对Call进行转化的对象
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // converterFactories 主要用于存储转化数据对象
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

client方法 则会调用callFactory方法给this.callFactory 赋值

 public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }


 public Builder callFactory(okhttp3.Call.Factory factory) {
     //赋值
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }

2.Call的创建过程

下面创建Retrofit实列并调用如下代码来生成接口的动态代理对象:

var apiserver=retrofit.create(ApiService::class.java)

看看retrofit的create方法:

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
      //返回一个Proxy.newProxyInstance动态代理对象,当我们调用ApiServier的 xxx方法时,最终会调用InvocationHandler的invoke方法
    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, 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);
            }
              //method 是我们定义在ApiServier里面的 xxx方法
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
             //这里发起请求
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

loadServiceMethod方法:

private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
  ServiceMethod<?, ?> loadServiceMethod(Method method) {
      //读取缓存
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
      //如果有缓存 直接返回
    if (result != null) return result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
          //没有创建一个,并加入serviceMethodCache缓存
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

再看ServiceMethod怎样构建的:

    public ServiceMethod build() {
     // 会最终得到们在构建Retrofit调用build方法时 adapterFactories添加对象的get方法 下面给出了说明
      callAdapter = createCallAdapter();
     //得到的是返回数据的真是类型
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
   //来遍历converterFactory列表中存储的Converter.Factory,并返回一个合适的Converter用来转换对象
   //在构建Retrorfit调用了addConverterFactory(GsonConverterFactory.create()),将GsonConverterFactory(Converter.Factory的子类)添加到converterFactories列表中,表示返回的数据支持转换为JSON对象
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
     //方法来对请求方式(比如GET、POST)和请求地址进行过解析 会调用->  parseHttpMethodAndPath()
        parseMethodAnnotation(annotation);
      }
     
      ...
      //对方法中的参数注解进行解析 比如(@Query、@Part)
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      ...
 
      return new ServiceMethod<>(this);
    }

ServiceMethod :包含所有网络请求信息的对象

Retrofit的build部分代码:

List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
 //adapterFactories 默认会添加defaultCallAdapterFactory。
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

defaultCallAdapterFactory指的是ExecutorCallAdapterFactory

  CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

ExecutorCallAdapterFactory的get方法:

 @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
  //返回CallAdapter对象
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
    //返回数据的真是类型
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
  //创建 ExecutorCallbackCall 作用 将call的回调转发至UI线程
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

responseType 比如 传入Call<xxxBean>,responseType方法就会返回xxxBean。

再看ExecutorCallbackCall方法:

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

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");
//方法最终调用delegate的enqueue方法。delegate是传入的OkHttpCall
      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 {
                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);
            }
          });
        }
      });
    }

主要是实现了Call接口 和对Call接口的封装,他主要添加了通过Retrofit的callbackExecutor将请求回调到UI线程,Call会调用他的enqueue方法,其实调用的是ExecutorCallbackCall的enqueue

3.Call的enqueue方法

来看OkHttpCall的enqueue

  @Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");

    okhttp3.Call call;
    Throwable failure;

    ... 
  //调用okhttp3的call的enqueue
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
 
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

parseResponse方法 返回一个response

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

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
//解析数据返回body,在此前例子 我们传入的是GsonConverterFactory
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

根据返回的的不同状态吗code来做不同操作,

总结:Call的enqueue方法主要是用于OkHttp来请求网络,将返回的Response进行数据转换并回调给UI线程。

写的不是很好 欢迎各位大佬交流指点

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

推荐阅读更多精彩内容