Retrofit 學習筆記

前言

Retrofit是個極其優(yōu)秀的庫,特別是和rxjava結合起來爽航,使用起來那是一個絲滑般爽审姓。不過使用了一兩年廷雅,現在才好好想起總結總結奏纪,下面直接用實際項目中的部分代碼來進行分析Retrofit幫我們做了什么壳鹤。

簡單的使用

  1. 創(chuàng)建Retrofit
        Retrofit.Builder().baseUrl(BuildConfig.HOST)
                .client(OKHTTP_CLIENT_NO_TOKEN)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()
  1. 創(chuàng)建含有網絡請求信息的ApiService
  2. 獲取ApiService
    fun getApiService(): ApiService = RETROFIT.create(ApiService::class.java)
  3. 調用ApiService 接口方法

Builder 過程

Retrofit 通過 Builder 模式創(chuàng)建:
先來直接看 Builder.build方法:

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

這是標準的build函數盛龄,檢測一些可配置參數,沒有設置就是賦默認值,然后創(chuàng)建目標對象余舶。

創(chuàng)建Retrofit對象6個參數

這里創(chuàng)建Retrofit需要6個參數:

1. callFactory:okhttp3.Call.Factory

這里是我們傳入的OkHttpClient 對象啊鸭,如果我們沒有傳入,build方法會為我們創(chuàng)建一個默認的OkhttpClient對象匿值。

2. baseUrl:HttpUrl

我們傳入host字符串后會經過HttpUrl.parse(baseUrl);處理后轉換為HttpUrl對象赠制。

3. converterFactories:List<Converter.Factory>

  1. Converter.Factory 是什么?挟憔。
    CallAdapter.Factory是個抽象類:
    里面有三個方法:

    • responseBodyConverter()返回Converter<ResponseBody, ?>對象(負責把ResponseBody對象轉為其他對象)
    • requestBodyConverter()返回Converter<?, RequestBody>對象(負責把其他對象轉為RequestBody)
    • stringConverter()返回Converter<?,String>對象(把其他對象轉為String對象)

    其中Converter<F,T>對象是個轉換接口钟些,里面convert方法,負責把F轉換為T對象绊谭。

  2. converterFactories 里面有哪些對象政恍?

    1. BuiltInConverters 對象
      在builder的構造方法里面創(chuàng)建了BuiltInConverters對象并添加到集合里面
    Builder(Platform platform) {
       this.platform = platform;
       // Add the built-in converter factory first. This prevents overriding its behavior but also
       // ensures correct behavior when using converters that consume all types.
       converterFactories.add(new BuiltInConverters());
     }
    
    1. GsonConverterFactory 對象
      在上面配置中我們添加了GsonConverterFactory.create() 實際是GsonConverterFactory 對象

4. adapterFactories:List<CallAdapter.Factory>

  1. CallAdapter.Factory 是什么?
    一個抽象類达传,里面也是3個方法
    a. get():CallAdapter 返回一個CallAdapter 適配器對象(有兩個方法篙耗,一返回Type,二把Call轉為其他對象的adapter方法)
    b. getParameterUpperBound() :Type 返回參數上限類型
    c. getRawType 獲取原始類型

  2. adapterFactories里面對象是什么宪赶?
    a. RxJava2CallAdapterFactory 對象
    在前面配置中.addCallAdapterFactory(RxJava2CallAdapterFactory.create())實際是RxJava2CallAdapterFactory對象
    b. ExecutorCallAdapterFactory 對象
    在build方法中會執(zhí)行adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); 宗弯,里面實際創(chuàng)建的是ExecutorCallAdapterFactory對象。

5. callbackExecutor:Executor

回調執(zhí)行者逊朽。

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

而platform變量在builder構造方法中被初始化罕伯,Android平臺下是Android對象,而platform.defaultCallbackExecutor();獲得的是MainThreadExecutor對象

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

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

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

6. validateEagerly:boolean

默認為false

create 方法做了什么

在剛開始用Retrofit時候一直很好奇叽讳,我們創(chuàng)建ApiService接口追他,沒有創(chuàng)建任何實現對象,經過Create方法就可以直接調用接口的方法岛蚤。
它這個方法里面做了什么呢邑狸。
來看下create的代碼:

  public <T> T create(final Class<T> service) {
  //驗證是否是接口
    Utils.validateServiceInterface(service);
    //前面?zhèn)魅氲膮担瑸閒alse
    if (validateEagerly) {
     // 如果為true涤妒,會執(zhí)行eagerlyValidateMethods方法单雾,
     //里面會遍歷接口的方法,創(chuàng)建對應的ServiceMethod對象并加到換成中
      eagerlyValidateMethods(service);
    }
    // 關鍵點K稀9瓒选!創(chuàng)建動態(tài)代理對象
    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);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

這個方法主要分3部分贿讹,第一部分驗證傳入的class是否是接口渐逃,第二部分根據builder中參數是否預先創(chuàng)建ServiceMethod對象,而第三部分是最為重要的民褂,創(chuàng)建動態(tài)代理對象茄菊。

動態(tài)代理Proxy

理解動態(tài)代理的同學疯潭,這部分可以跳過。面殖。竖哩。。
簡單的介紹下動態(tài)代理脊僚,利用反射技術在運行時候創(chuàng)建給定接口的動態(tài)代理對象實例相叁。而創(chuàng)建這種代理對象也很簡單,
Proxy.newProxyInstance()

里面接受3個參數:

  1. ClassLoader 類加載器
  2. Class<?>[] interfaces 接口class 數組
  3. InvocationHandler 接口吃挑。

invoke 方法有3個參數:

  1. proxy:Object 動態(tài)代理對象钝荡,可用來獲取類信息,方法舶衬,annotation等
  2. method:Method 被代用的方法埠通,可獲取方法名,參數逛犹,返回類型等信息
  3. args:Object[] 方法參數

而動態(tài)代理類的方法都會交給實現了InvocationHandler接口對象的invoke()處理端辱。所以我們使用Retrofit創(chuàng)建了ApiService 代理對象。然后調用里面的方法時候其實是調用invoke方法

Retrofit中create方法內InvocationHandler對象的invoke方法

上面我們已經搞起動態(tài)代理是什么東西虽画,而Retrofit之所以能幫我們實現接口定義的方法就是因為這里面的invoke舞蔽。

          @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);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }

前面兩個判斷是保證后面的執(zhí)行的我們定義的方法。后面才是重點码撰,
這里也分了3個步驟:

  1. 根據method 加載得到ServiceMethod
  2. 創(chuàng)建 OkHttpCall 對象渗柿。
  3. 調用 serviceMethod.callAdapter.adapt(okHttpCall)

ServiceMethod 是什么?

ServiceMethod 其實是個適配器脖岛,把我們接口定義的方法轉為 http call朵栖。
里面除了一個Builder類還有3個重要的方法:

  1. toRequest():Request 生成請求
  2. toResponse():Response 生成響應
  3. parsePathParameters():Set<String> 解析路徑參數

先來看下serviceMethod怎么得到的,在invoke中調用了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 = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

上面可看到柴梆,如果緩存中有就直接使用陨溅,沒有就通過new ServiceMethod.Builder<>(this, method).build();創(chuàng)建。

ServiceMethod 的創(chuàng)建

先來分析下ServiceMethod的創(chuàng)建過程绍在,上文知道先創(chuàng)建Builder對象然后調用build方法门扇。

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

這個構造方法做的事情比較簡單,就五個成員變量賦值偿渡,分別是Retrofit對象臼寄,方法對象,方法注解溜宽,參數類型脯厨,參數注解(二維數組)

  1. build 方法

這個方法比較長,我們省略一些異常步驟:

    public ServiceMethod build() {
      // 獲取callAdapter
      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?");
      }
      // 賦值響應轉換器
      responseConverter = createResponseConverter();
      // 解析方法注解
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      ...
      確保請求方式坑质,請求體等信息正確
      ...
      // 方法參數數量
      int parameterCount = parameterAnnotationsArray.length;
      // 參數交給 ParameterHandler處理
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      ...
      確保請求參數信息正確
      ...
      // 創(chuàng)建 ServiceMethod 對象
      return new ServiceMethod<>(this);
    }

來大概過一下這個build方法合武,先獲取callAdapter->再通過Retrofit獲取Converter<Response,?>轉換器->解析方法注解獲取請求方式->解析方法參數獲取請求參數->構成ServiceMethod對象。

2.1 callAdapter 是什么對象涡扼?
createCallAdapter方法內最終通過(CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);獲取callAdapter對象稼跳,最終調用Retrofit的nextCallAdapter方法:

  public CallAdapter<?, ?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");
    //skipPast = null 所以是-1+1 = 0
    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;
      }
    }

這里會返回adapterFactories集合中第一個適配器工廠類返回的適配器,RxJava2CallAdapterFactory(如果沒有添加rxjava那就是默認的工廠類 ExecutorCallAdapterFactory 類)吃沪,查看RxJava2CallAdapterFactory對象的get方法汤善,發(fā)現返回的是RxJava2CallAdapter對象。

所以callAdapter是RxJava2CallAdapter對象(如果沒添加rxjava票彪,使用默認红淡,這個對象是CallAdapter匿名子類)。

2.2 responseConverter 是什么對象降铸?

同樣ServiceMethod的 createResponseConverter 方法最終會調用 Retrofit的responseBodyConverter方法
retrofit.responseBodyConverter(responseType, annotations);
最終調用nextResponseBodyConverter方法:

  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
      Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }
    ....
    ....
  }

這里的邏輯和nextCallAdapter類似在旱,不過converterFactories中的第一個對象是BuiltInConverters,它的responseBodyConverter方法當方法返回類型不是ResponseBody或Void時候返回空的Converter對象推掸。

public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    if (type == ResponseBody.class) {
      return Utils.isAnnotationPresent(annotations, Streaming.class)
          ? StreamingResponseBodyConverter.INSTANCE
          : BufferingResponseBodyConverter.INSTANCE;
    }
    if (type == Void.class) {
      return VoidResponseBodyConverter.INSTANCE;
    }
    return null;
  }

所以我們看下GsonConverterFactory :

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

所以我們等下用GsonResponseBodyConverter分析桶蝎。

2.3 解析方法 注解

主要是parseMethodAnnotation方法:

  private void parseMethodAnnotation(Annotation annotation) {
      ....
      else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } 
      ....
    }

里面對不同類型注解進行處理,最終都是交給parseHttpMethodAndPath方法谅畅,我們以GET為例子登渣。

 private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      ...
      ...
      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }

其實里面是獲取注解內的信息然后存儲在成員變量中

2.4 解析方法參數注解

主要是生成 parameterHandler,parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);

而parseParameter方法最終調用parseParameterAnnotation方法生成 ParameterHandler

而ParameterHandler是個抽象類毡泻,不同注解有不同實現

OkHttpCall 對象

構造器里面接受ServiceMethod 與 方法參數

RxJava2CallAdapter 的 adapter 方法

最后create方法返回的是serviceMethod.callAdapter.adapt(okHttpCall) 對象

  @Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }

這里返回不同的Rx 被觀察者對象 胜茧,我們以CallExecuteObservable為例看看里面怎么執(zhí)行的

CallExecuteObservable 訂閱方法

熟悉Rxjava的同學都知道,當Observable被訂閱時候仇味,會執(zhí)行Observable的subscribeActual方法呻顽,我先來看下CallExecuteObservable的subscribeActual方法:

 @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    // okhttpCall 對象
    Call<T> call = originalCall.clone();
    observer.onSubscribe(new CallDisposable(call));

    boolean terminated = false;
    try {
      // 重要步驟,發(fā)送網絡請求獲取響應
      Response<T> response = call.execute();
      if (!call.isCanceled()) {
        observer.onNext(response);
      }
      if (!call.isCanceled()) {
        terminated = true;
        observer.onComplete();
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (terminated) {
        RxJavaPlugins.onError(t);
      } else if (!call.isCanceled()) {
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }
  }

可以看到里面有個重要的步驟Response<T> response = call.execute();
通過OkhttpCall的execute方法獲取響應然后進行后面Rx的onNext等步驟邪铲。

OkhttpCall 的execute 方法

來看下實際執(zhí)行網絡請求:

 @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

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

      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else {
          throw (RuntimeException) creationFailure;
        }
      }

      call = rawCall;
      if (call == null) {
        try {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          creationFailure = e;
          throw e;
        }
      }
    }

    if (canceled) {
      call.cancel();
    }

    return parseResponse(call.execute());
  }

可以看到里面其實分3個工作:

  1. 創(chuàng)建Okhttp3.Call
  2. 執(zhí)行execute獲取響應
  3. 執(zhí)行parseResponse 轉換響應

而其中execute獲取響應是調用Okhttp中的方法芬位,所以我們來分析下其他兩個步驟:

  • createRawCall 得到okhttp.Call
  private okhttp3.Call createRawCall() throws IOException {
    // 獲取請求
    Request request = serviceMethod.toRequest(args);
    // 其實是OkhttpClient.newCall()方法
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

終于看見關鍵步驟了,這方法里先通過serviceMethod 獲取請求带到,而service.callFactory是調用Retrofit中的callFactory昧碉,也就是我們build中傳入的OkhttpClient對象,所以其實Retrofit還是通過Okhttp進行網絡請求揽惹。

  • 執(zhí)行parseResponse

前面已經獲取了原始的響應了被饿,怎么獲取


  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.
    // 讓響應source可傳遞
    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();
      }
    }
    // 204,205 響應成功,無數據
    if (code == 204 || code == 205) {
      rawBody.close();
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      // 獲取響應搪搏,把響應體的包裝類通過serviceMethod處理
      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;
    }
  }

上面分析可以看到原始的響應體經過serviceMethod.toResponse(catchingBody);處理變成我們想要的數據狭握。然后把得到的數據包裝成Response(并非ok中的Response)對象。

而ServiceMethod中的toResponse也很簡單:

  R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

而responseConverter對象在之前分析了是GsonResponseBodyConverter,所以我們看下它的convert方法:

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }

這就是可以得到們要想對bean類的原因疯溺。

總結

至此论颅,我們Retrofit的流程分析的差不多了“タ眩現在來總結下流程:

  1. 通過Retrofit.Builder 生成Retrofit對象(主要傳入,baseUrl恃疯,OkhttpClient漏设,coverter,callAdapter等)今妄。
  2. 調用create方法得到接口的代理對象郑口。
  3. 執(zhí)行接口的某個方法觸發(fā)代理對象的invoke方法。
  4. 通過Builder模式盾鳞,生成 ServiceMethod 對象(期間犬性,進行變量賦值,解析方法中注解path腾仅,解析請求參數等信息)
  5. 生成OkhttpCall 對象
  6. 執(zhí)行callAdapter 中的 adapter 方法(后續(xù)以RxJava2CallAdapter為例)
  7. 生成XXXObservable等被觀察者對象(后續(xù)以CallExecuteObservable為例)
  8. 下游訂閱執(zhí)行 subscribeActual 方法
  9. 執(zhí)行OkhttpCall方法生成響應(期間使用serviceMethod生成Okhttp的Request乒裆,經過Okhttpclien得到call對象,然后生成原始Response攒砖,然后使用serviceMethod中的converter轉換原始響應得到Gson處理后的響應數據)
  10. 完成一次請求缸兔。
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吹艇,隨后出現的幾起案子惰蜜,更是在濱河造成了極大的恐慌,老刑警劉巖受神,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抛猖,死亡現場離奇詭異,居然都是意外死亡鼻听,警方通過查閱死者的電腦和手機财著,發(fā)現死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撑碴,“玉大人撑教,你說我怎么就攤上這事∽硗兀” “怎么了伟姐?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長亿卤。 經常有香客問我愤兵,道長,這世上最難降的妖魔是什么排吴? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任秆乳,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘屹堰。我一直安慰自己肛冶,他們只是感情好,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布双藕。 她就那樣靜靜地躺著淑趾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪忧陪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天近范,我揣著相機與錄音嘶摊,去河邊找鬼。 笑死评矩,一個胖子當著我的面吹牛叶堆,可吹牛的內容都是我干的。 我是一名探鬼主播斥杜,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼虱颗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蔗喂?” 一聲冷哼從身側響起忘渔,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缰儿,沒想到半個月后畦粮,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡乖阵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年宣赔,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瞪浸。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡儒将,死狀恐怖,靈堂內的尸體忽然破棺而出对蒲,到底是詐尸還是另有隱情钩蚊,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布齐蔽,位于F島的核電站两疚,受9級特大地震影響,放射性物質發(fā)生泄漏含滴。R本人自食惡果不足惜诱渤,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谈况。 院中可真熱鬧勺美,春花似錦递胧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至占卧,卻和暖如春遗菠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背华蜒。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工辙纬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叭喜。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓贺拣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親捂蕴。 傳聞我的和親對象是個殘疾皇子譬涡,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內容