Android源碼系列-解密Retrofit

Retrofit是什麼?

簡介

Retrofit,中文的翻譯爲「式樣翻新」的意思,是一個基於OKHttp的RESTful網絡請求框架。通俗一點來講,Retrofit就是一個網絡請求框架的封裝。一樣是由Square公司開源的Android熱門網絡框架之一,其具備功能強大、簡潔易用及高可拓展性特色。java

官網網址:Retrofit官網git

Github地址:Githubgithub

特色

一、基於OkHttp並遵循Restful API設計風格json

二、經過註解的形式,可簡便的配置網絡請求參數設計模式

三、支持同步及異步的網絡請求方式緩存

四、支持RxJavabash

五、支持多種數據格式的解析(Json、XML、Protobuf等)微信

Retrofit怎麼用?

一、gradle引入庫網絡

implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0' //配置使用Gson解析響應數據 可選
implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0' //配置支持RxJava 可選
複製代碼

二、初始化Retrofit對象app

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL) //配置baseUrl
                .addConverterFactory(GsonConverterFactory.create()) //配置使用Gson解析響應數據
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //配置支持RxJava
                .build();
複製代碼

網絡接口定義

public interface WeatherService {
        //使用GET請求 直接返回原始數據
        @GET("weather?location=%E5%98%89%E5%85%B4&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ")
        Call<ResponseBody> cityNameQueryWeather();
        
        //使用GET請求 返回Json映射對象
        @GET("{weather}?location=%E5%98%89%E5%85%B4&output=json")
        Call<WeatherResp> cityWeatherPath(@Path("weather") String weather, @Query("ak") String ak);
        
       //使用POST請求 支持RxJava返回
        @FormUrlEncoded()
        @POST("{weather}")
        rx.Observable<WeatherResp> cityWeatherPost(@Path("weather") String weather, @Field("ak") String ak, @Field("location") String location, @Field("output") String output);
        
        }
複製代碼

同步請求

WeatherService weatherService = retrofit.create(WeatherService.class);
        Call<ResponseBody> responseBodyCall = weatherService.cityNameQueryWeather();
        try {
            Response<ResponseBody> responseBody = responseBodyCall.execute();
            System.out.println("call:" + responseBody.body().string());

        } catch (IOException e) {
            e.printStackTrace();
        }
複製代碼

異步請求

WeatherService weatherService = retrofit.create(WeatherService.class);
        Call<WeatherResp> responseBodyCall = weatherService.cityWeatherPath("weather", "5slgyqGDENN7Sy7pw29IUvrZ");
        responseBodyCall.enqueue(new Callback<WeatherResp>() {
            @Override
            public void onResponse(Call<WeatherResp> call, Response<WeatherResp> response) {
                System.out.println("call:" + response.toString());
            }

            @Override
            public void onFailure(Call<WeatherResp> call, Throwable t) {

            }
        });
複製代碼

RxJava支持

WeatherService weatherService = retrofit.create(WeatherService.class);
        weatherService.rxCityWeatherPost("weather", "5slgyqGDENN7Sy7pw29IUvrZ", "%E5%98%89%E5%85%B4", "json")
                .subscribeOn(Schedulers.io())        //在新線程裏面處理網絡請求
                .observeOn(AndroidSchedulers.mainThread())  //在主線程裏面接受返回的數據
                .subscribe(new rx.Observer<WeatherResp>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(WeatherResp weatherResp) {
                        System.out.println("call:" + weatherResp.toString());
                    }
                });
複製代碼

詳細的Retrofit的註解配置及各註解的使用,推薦參考

這是一份很詳細的 Retrofit 2.0 使用教程(含實例講解)

Retrofit核心執行流程是怎樣?

關鍵類功能說明

功能說明
Retrofit 裏面包含了不少對象,serviceMethodCache(自定義的接口映射對象集合)、baseUrl(請求地址)、callFactory(默認爲OKHttpCall)、converterFactories(數據解析器工廠集合)、callAdapterFactories(Call適配器工廠集合)、callbackExecutor(回調執行,Android平臺默認爲MainThreadExecutor)使用Builder模型構建
Platform Retrofit中用來管理多平臺的方法,支持Android、Java8。經過findPlatform獲取對應的平臺,同時也初始化了defaultCallAdapterFactory工廠
ServiceMethod 接口映射的網絡請求對象,經過動態代理,將自定義接口的標註轉換爲該對象,將標註及參數生成OkHttp所需的Request對象。Retrofit的create經過動態代理攔截,將每個自定義接口轉換成爲一個ServiceMethod對象,並經過經過serviceMethodCache進行緩存。
Call Retrofit定義的網絡請求接口,包含execute、enqueue等方法
OkHttpCall Ohttp的Call實現,經過createRawCall獲得真正的 okhttp3.Call對象,用於進行實際的網絡請求
CallAdapter.Factory CallAdapter的靜態工廠,包含get的抽象方法,用於生產CallAdapter對象
ExecutorCallAdapterFactory Android平臺默認的CallAdapter工廠,get方法使用匿名內部類實現CallAdapter,返回ExecutorCallbackCall,實現了Call
ExecutorCallbackCall 採用靜態代理設計,delegate實際爲OkHttpCall,使用callbackExecutor實現回調在主線程中執行
RxJavaCallAdapterFactory Rxjava平臺的CallAdapter工廠,get方法返回RxJavaCallAdapter對象
RxJavaCallAdapter Rxjava平臺的設配器,返回observable對象
Converter.Factory 數據解析器工廠,用於生產Converter實例
GsonConverterFactory 數據解析工廠實例,返回了GsonResponseBodyConverter數據解析器
GsonResponseBodyConverter Gson的數據解析器,將服務端返回的json對象轉換成對應的java模型
Response Retrofit網絡請求響應的Response

代碼執行流程

image

  1. 經過Build模式構建Retrofit對象
  2. 自定義的接口interface,包含接口方法及相關標註
  3. 執行定義的接口方法
  4. 經過Proxy.newProxyInstance進行動態代理攔截
  5. 經過反射將定義的標註方法解析生成ServiceMethod對象(表示一個網絡請求的封裝對象)並加入serviceMethodCache隊列中,避免重複解析
  6. 建立OkHttpCall對象, 繼承了Call接口,橋接okhttp3.Call rawCall
  7. 從Retrofit對象的callAdapterFactories工廠集合獲取CallAdapter,並調用adapt方法。若是是默認的使用ExecutorCallAdapterFactory設配返回Call,若是設置了RxJavaCallAdapterFactory,返回observable。
  8. 獲取適配器轉換後的對象,執行同步請求或者異步請求。
  9. 建立Okhttp的RealCall對象
  10. 經過反射的arg參數,調用serviceMethod.toCall(),構建生成Okhttp的RealCall所須要的Request對象
  11. 經過OkHttp的RealCall執行對應的同步或異步請求
  12. 請求成功,經過parseResponse解析請求參數
  13. 經過數據轉換器responseConverter.convert(body),將原始數據轉換爲對象
  14. 回調解析完的數據對象Respone(T)
  15. Retrofit 如何將定義的interface轉換成網絡請求?

    咱們都知道,Retrofit經過自定義interface及相關的標註來描述一個http的請求,使用很是簡便,且易於維護。

    這是Retrofit設計的精髓之一,,當調用Retrofit的create()方法時,會進行動態代理監聽。當執行具體的接口方法時,會回調InvocationHandler。經過反射解析method的標註及參數,生成ServiceMethod對象,ServiceMethod中封裝了OKHttp網絡請求所需的相關參數。

    源碼實現以下:

    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();
    
              @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);
                }
                //生成ServiceMethod
                ServiceMethod<Object, Object> serviceMethod =o
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.adapt(okHttpCall);
              }
            });
      }
    複製代碼

    經過源碼咱們知道,具體的轉換方法爲 (ServiceMethod<Object, Object>) 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 = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    複製代碼

    經過Builder構建模式,建立一個ServiceMethod對象,並加入緩存,具體的構造實現以下:

    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();
          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);
          }
    
          if (httpMethod == null) {
            throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
          }
    
          if (!hasBody) {
            if (isMultipart) {
              throw methodError(
                  "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
            }
            if (isFormEncoded) {
              throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
                  + "request body (e.g., @POST).");
            }
          }
    
          int parameterCount = parameterAnnotationsArray.length;
          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);
          }
    
          if (relativeUrl == null && !gotUrl) {
            throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
          }
          if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
            throw methodError("Non-body HTTP method cannot contain @Body.");
          }
          if (isFormEncoded && !gotField) {
            throw methodError("Form-encoded method must contain at least one @Field.");
          }
          if (isMultipart && !gotPart) {
            throw methodError("Multipart method must contain at least one @Part.");
          }
    
          return new ServiceMethod<>(this);
        }
    複製代碼

    build()方法會經過反射去解析method的標註、參數的類型等。詳細的解析可參考源碼ParameterHandler相關實現,這裏主要對流程進行剖析。

    總結一下,Retrofit經過自定義interface及相關的標註來描述一個http的請求,當調用Retrofit的create()方法時,會進行動態代理監聽。當執行具體的接口方法時,會回調InvocationHandler。經過反射解析method的標註及參數,生成ServiceMethod對象,ServiceMethod中封裝了OKHttp網絡請求所需的相關參數。這就是Retrofit將定義的interface轉換成網絡請求對象的過程。

    Retrofit的Converter機制是如何實現?

    Converter種類

    Retrofit支持多種數據解析方式,使用時須要在Gradle添加依賴。

    數據解析器 Gradle依賴
    Gson com.squareup.retrofit2:converter-gson:2.4.0
    Jackson com.squareup.retrofit2:converter-jackson:2.4.0
    Simple XML com.squareup.retrofit2:converter-simplexml:2.4.0
    Protobuf com.squareup.retrofit2:converter-protobuf:2.4.0
    Moshi com.squareup.retrofit2:converter-moshi:2.4.0
    Wire com.squareup.retrofit2:converter-wire:2.4.0
    Scalars com.squareup.retrofit2:converter-scalars:2.4.0

    Converter實現流程

    添加Converter工廠

    首先在Retrofit的初始化添加Converter,addConverterFactory(GsonConverterFactory.create())。具體實現以下:

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

    將Converter的工廠加入到converterFactories集合中。

    觸發數據轉換

    經過上述的流程分析,咱們知道Retrofit當網絡請求成功後會執行,OkHttpCall中的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. 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 { 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; } } 複製代碼

    其中關鍵的代碼爲 T body = serviceMethod.toResponse(catchingBody),具體實現以下:

    /** Builds a method return value from an HTTP response body. */
      R toResponse(ResponseBody body) throws IOException {
        return responseConverter.convert(body);
      }
    複製代碼

    數據轉換器的建立

    這裏就是 Converter實現轉換的地方,那麼responseConverter在哪裏進行初始化呢?在ServiceMethod的Build方法中,會調用createResponseConverter()進行數據解析器的建立,實現以下:

    private Converter<ResponseBody, T> createResponseConverter() {
          Annotation[] annotations = method.getAnnotations();
          try {
            return retrofit.responseBodyConverter(responseType, annotations);
          } catch (RuntimeException e) { // Wide exception range because factories are user code.
            throw methodError(e, "Unable to create converter for %s", responseType);
          }
        }
    複製代碼

    調用了 retrofit.responseBodyConverter方法

    public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
        return nextResponseBodyConverter(null, type, annotations);
      }
    
    複製代碼

    調用了 retrofit.nextResponseBodyConverter方法

    public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
          @Nullable 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;
          }
        }
    
        StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
            .append(type)
            .append(".\n");
        if (skipPast != null) {
          builder.append(" Skipped:");
          for (int i = 0; i < start; i++) {
            builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
          }
          builder.append('\n');
        }
        builder.append(" Tried:");
        for (int i = start, count = converterFactories.size(); i < count; i++) {
          builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
        }
        throw new IllegalArgumentException(builder.toString());
      }
    複製代碼

    經過Retrofit的converterFactories工廠集合匹配獲取開始添加的數據轉換工廠

    默認的數據轉換工廠

    經過Retrofit build() 中發現以下代碼,converterFactories.add(new BuiltInConverters()),可知Retrofit默認的數據轉換器工廠爲BuiltInConverters。主要實現以下:

    @Override
      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;
      }
    
    複製代碼

    會將數據轉換爲ResponseBody對象,因此若是Retrofit默認不使用任何數據解析器,定義interface方法時接收數據對象使用 Call。

    Retrofit的CallAdapter機制是如何實現?

    Retrofit支持多種網絡請求適配器方式:guava、Java8和rxjava 。Android默認的適配器工廠爲ExecutorCallAdapterFactory,最後的回調經過ExecutorCallbackCall切換至主線程運行。

    CallAdapter種類

    網絡請求適配器 Gradle依賴
    guava com.squareup.retrofit2:adapter-guava:2.4.0
    Java8 com.squareup.retrofit2:adapter-java8:2.4.0
    rxjava com.squareup.retrofit2:adapter-rxjava:2.4.0

    CallAdapter實現流程

    添加CallAdapter工廠

    首先在Retrofit的初始化添加CallAdapter工廠,addCallAdapterFactory(RxJavaCallAdapterFactory.create())。具體實現以下:

    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
          callAdapterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    複製代碼

    將CallAdapter的工廠加入到callAdapterFactories集合中。

    CallAdapter的adapt實現

    經過上述Retrofit的create方法中分析可知,當攔截到interface的方法調用後最後會執行 return serviceMethod.adapt(okHttpCall)。adapt的實現以下:

    T adapt(Call<R> call) {
        return callAdapter.adapt(call);
      }
    複製代碼

    就是在這個地方觸發了callAdapter的adapt方法。返回最終適配的具體對象。

    默認的CallAdapter工廠

    Android平臺默認的CallAdapter工廠爲ExecutorCallAdapterFactory。經過Retrofit的build()方法可知:

    // Make a defensive copy of the adapters and add the default Call adapter.
          List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
          callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    複製代碼

    platform.defaultCallAdapterFactory的實現以下:

    CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        if (callbackExecutor != null) {
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
        return DefaultCallAdapterFactory.INSTANCE;
      }
    複製代碼

    ExecutorCallAdapterFactory的CallAdapter建立以下:

    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            if (getRawType(returnType) != Call.class) {
                return null;
            } else {
                final Type responseType = Utils.getCallResponseType(returnType);
                return new CallAdapter<Object, Call<?>>() {
                    public Type responseType() {
                        return responseType;
                    }
    
                    public Call<Object> adapt(Call<Object> call) {
                        return new ExecutorCallAdapterFactory.ExecutorCallbackCall(ExecutorCallAdapterFactory.this.callbackExecutor, call);
                    }
                };
            }
        }
    複製代碼

    adapt方法最後返回仍是Call對象,具體的適配實現由ExecutorCallbackCall執行,具體源碼以下:

    static final class ExecutorCallbackCall<T> implements Call<T> {
            final Executor callbackExecutor;
            final Call<T> delegate;
    
            ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
                this.callbackExecutor = callbackExecutor;
                this.delegate = delegate;
            }
    
            public void enqueue(final Callback<T> callback) {
                Utils.checkNotNull(callback, "callback == null");
                this.delegate.enqueue(new Callback<T>() {
                    public void onResponse(Call<T> call, final Response<T> response) {
                        ExecutorCallbackCall.this.callbackExecutor.execute(new Runnable() {
                            public void run() {
                                if (ExecutorCallbackCall.this.delegate.isCanceled()) {
                                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                                } else {
                                    callback.onResponse(ExecutorCallbackCall.this, response);
                                }
    
                            }
                        });
                    }
    
                    public void onFailure(Call<T> call, final Throwable t) {
                        ExecutorCallbackCall.this.callbackExecutor.execute(new Runnable() {
                            public void run() {
                                callback.onFailure(ExecutorCallbackCall.this, t);
                            }
                        });
                    }
                });
            }
    
           
    
            public Response<T> execute() throws IOException {
                return this.delegate.execute();
            }
    }
    複製代碼

    具體的執行仍是經過delegate(OkHttpCall)來執行,可是在回調使用了 ExecutorCallbackCall.this.callbackExecutor.execute()方法,Android平臺的callbackExecutor實現爲MainThreadExecutor。具體源碼以下:

    static class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override public void execute(Runnable r) {
            handler.post(r);
          }
        }
    複製代碼

    因此ExecutorCallAdapterFactory中適配最後的設配對象仍是Call,實現仍是OkHttpCall,經過 MainThreadExecutor,將回調切換在UI線程中運行

    CallAdapter的建立

    在ServiceMethod的Build方法中,createCallAdapter()進行適配器的的建立,實現以下:

    private CallAdapter<T, R> createCallAdapter() {
          Type returnType = method.getGenericReturnType();
          if (Utils.hasUnresolvableType(returnType)) {
            throw methodError(
                "Method return type must not include a type variable or wildcard: %s", returnType);
          }
          if (returnType == void.class) {
            throw methodError("Service methods cannot return void.");
          }
          Annotation[] annotations = method.getAnnotations();
          try {
            //noinspection unchecked
            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);
          }
        }
    複製代碼

    調用了 retrofit.callAdapter

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

    調用了 retrofit.nextCallAdapter

    public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
         Annotation[] annotations) {
       checkNotNull(returnType, "returnType == null");
       checkNotNull(annotations, "annotations == null");
    
       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;
         }
       }
    
       StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
           .append(returnType)
           .append(".\n");
       if (skipPast != null) {
         builder.append(" Skipped:");
         for (int i = 0; i < start; i++) {
           builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
         }
         builder.append('\n');
       }
       builder.append(" Tried:");
       for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
         builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
       }
       throw new IllegalArgumentException(builder.toString());
     }
    複製代碼

    經過Retrofit的callAdapterFactories工廠集合匹配獲取開始添加的適配器工廠

    如何自定義一個Converter及CallAdapter?

    自定義Converter

    一、須要定義一個工廠類繼承Converter.Factory

    二、複寫responseBodyConverter及requestBodyConverter方法

    三、在Retrofit定義時加入自定義的Converter,addConverterFactory(new CustomConverterFactory())

    /**
     * @author allen
     * @date 2018/8/7
     * 返回服務端返回的string結果
     */
    public class CustomConverterFactory extends Converter.Factory {
    
        @Nullable
        @Override
        public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
            return StringResponseBodyConverter.INSTANCE;
        }
        @Nullable
        @Override
        public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
            return StringRequestBodyConverter.INSTANCE;
        }
    
        static final class StringResponseBodyConverter implements Converter<ResponseBody, String> {
            static final CustomConverterFactory.StringResponseBodyConverter INSTANCE = new CustomConverterFactory.StringResponseBodyConverter();
    
            @Override
            public String convert(ResponseBody value) {
    
                try {
                    System.out.println("CustomConverterFactory");
                    return value.string();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return "";
            }
        }
        static final class StringRequestBodyConverter implements Converter<RequestBody, RequestBody> {
            static final CustomConverterFactory.StringRequestBodyConverter INSTANCE = new CustomConverterFactory.StringRequestBodyConverter();
    
            @Override
            public RequestBody convert(@NonNull RequestBody value) {
                return value;
            }
        }
    }
    複製代碼

    自定義CallAdapter

    一、須要定義一個工廠類繼承CallAdapter.Factory

    二、複寫CallAdapter get方法

    三、在Retrofit定義時加入自定義的CallAdapter, addCallAdapterFactory(new CustomCallAdapterFactory())

    /**
     * @author allen
     * @date 2018/8/7
     */
    public class CustomCallAdapterFactory extends CallAdapter.Factory {
        @Nullable
        @Override
        public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    
            return new CallAdapter<Object, Object>() {
                @Override
                public Type responseType() {
                    return String.class;
                }
    
                @Override
                public Object adapt(Call<Object> call) {
                    System.out.println("CustomCallAdapterFactory adapt(");
                    return call;
                }
            };
        }
    }
    
    複製代碼

    Retrofit中運用了那些設計模式?

    一、建造者模式

    Retrofit對象的建立、ServiceMethod對象建立都使用Build模式,將複雜對象的建立和表示分離,調用者不須要知道複雜的建立過程,使用Build的相關方法進行配置建立對象。

    二、外觀模式

    Retrofit對外提供了統一的調度,屏蔽了內部的實現,使得使用該網絡庫簡單便捷。

    三、動態代理模式

    經過動態代理的方式,當調用Retrofit的create()方法時,會進行動態代理監聽。當執行具體的接口方法時,會回調InvocationHandler。經過反射解析method的標註及參數,生成ServiceMethod對象。

    四、靜態代理模式 Android平臺默認的適配器ExecutorCallbackCall,採用靜態代理的模式。具體的實現delegate爲OkHttpCall。

    五、工廠模式 Converter及CallAdapter的建立都採用了工廠模式進行建立。

    六、適配器模式 CallAdapter的adapt採用了適配器模式,使得interface的返回對象能夠動態擴展,加強了靈活性

    總結

    思考

    大多數流行的開源框架都是通過頂級coder的設計,包含了不少精妙的設計。多學習分析,收益良多。

    參考資料

    這是一份很詳細的 Retrofit 2.0 使用教程(含實例講解)

    Android:手把手帶你深刻剖析 Retrofit 2.0 源碼

    推薦

    Android源碼系列-解密OkHttp

    Android源碼系列-解密Retrofit

    Android源碼系列-解密Glide

    Android源碼系列-解密EventBus

    Android源碼系列-解密RxJava

    Android源碼系列-解密LeakCanary

    Android源碼系列-解密BlockCanary

    關於

    歡迎關注個人我的公衆號

    微信搜索:一碼一浮生,或者搜索公衆號ID:life2code

    image

相關文章
相關標籤/搜索