Retrofit源碼解析

一,前言

Retrofit其實是將OKhttp封裝起來,和volley一樣。那解析Retrofit其實就是解析它如何封裝使用OKhttp,那我直接從其使用上來跟蹤源碼。

總體上可以分為四步:

  1. 創建Retrofit對象
  2. 通過Retrofit獲取接口對象
  3. 通過接口對象獲取請求服務的Call對象
  4. 最后通過Call的異步enqueue或同步execute來執行網絡請求并回調結果。

下面也是通過這四步來解析源碼

二,創建Retrofit對象

先占時不考慮RxJava的使用

Retrofit retrofit = new Retrofit.Builder()  //1
    .baseUrl(baseUrl)   //2
    .addConverterFactory(GsonConverterFactory.create()) //3
    .build();   //4

Retrofit是通過建造者模式來構建對象的,那很明顯,這里只是配置了請求網絡的參數而已,而這些配置在后面的網絡請求和結果轉換用到了。

第二步是為了配置請求服務的地址;第三部是配置返回結果的轉換器,使結果為對象。

2.1 Builder()

public static final class Builder {
    private final Platform platform;
    // 網絡請求器的工廠
    private @Nullable okhttp3.Call.Factory callFactory;
    // 網絡請求的url地址
    private HttpUrl baseUrl;
    // 數據轉換器工廠的集合,生產數據轉換器(converter)
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    // 網絡請求適配器工廠的集合,生產網絡請求適配器(CallAdapter)
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    //// 請求結束后回調方法的執行Executor
    private @Nullable Executor callbackExecutor;
    // 是否提前對業務接口中的注解進行驗證轉換的標志位
    private boolean validateEagerly;
    
    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());
    }
    
    public Builder() {
      this(Platform.get());
    }
    ...
}

Builder里存儲的參數都會在Retrofit創建時賦值給它,后面的build()再介紹。

在創建Builder()對象時,其實只賦值了兩個屬性:platform 和converterFactories。可以知道默認的請求結果轉換器為BuiltInConverters,我們開發中一般使用GsonConverterFactory.create()。

2.1.1 Platform

Platform是單例模式,通過Platform.get()來獲取對象。

class Platform {
  //單例對象是通過findPlatform()創建的
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      //如果是安卓系統,就返回Android()
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
     // Java8()
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
  
  static class Android extends Platform {
    //請求結果回調使用的Executor,如果Builder沒有賦值給callbackExecutor,就會調用這個方法賦值
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    //Builder里的CallAdapter.Factory,最后會在build()里賦值給adapterFactories,作為默認的網絡請求適配器
    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      //那可以看出默認的網絡適配器是ExecutorCallAdapterFactory實現的
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    //調用handler使回調在主線程執行
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

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

最為安卓平臺,Platform最終賦值的對象是靜態內部類Android,這個對象作為默認配置,會在Builder的build()方法中調用賦值。

defaultCallbackExecutor是返回回調執行的Executor,返回的MainThreadExecutor是使用handler讓回調操作在主線程執行。如果在Builder中沒有指定回調的Executor,會調用defaultCallbackExecutor指定異步網絡請求的回調在主線程執行

defaultCallAdapterFactory則是指定默認網絡適配器工廠為ExecutorCallAdapterFactory,調用接口方法返回的Call,就是這個類創建的。具體等后面使用其功能再介紹。

2.2 其它配置

2.2.1 baseUrl

就是將String類型的url,經過合格性檢測,拆分存儲,再轉換成HttpUrl賦值給baseUrl。

public Builder baseUrl(String baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
  //將String的轉為HttpUrl
  HttpUrl httpUrl = HttpUrl.parse(baseUrl);
  if (httpUrl == null) {
    throw new IllegalArgumentException("Illegal URL: " + baseUrl);
  }
  return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
  List<String> pathSegments = baseUrl.pathSegments();
  //如果路徑結尾不是以"/"結尾,會拋出異常
  if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
  }
  this.baseUrl = baseUrl;
  return this;
}

值得注意的是,路徑必須以"/"結尾

2.2.2 addConverterFactory

//將轉換工廠保存到converterFactories中,在構造器中,已經add了一個BuiltInConverters
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}

上面的例子是添加GsonConverterFactory,下面來看看它是如何轉換的。

2.2.2.1 GsonConverterFactory

public final class GsonConverterFactory extends Converter.Factory {

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

final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {

    @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      //將ResponseBody轉為泛型對象
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }

通過convert轉換的類型,是在調用responseBodyConverter創建對象時傳入的請求接口的返回類的泛型。也就是例子中的HttpResult。

如果要自定義Converter來實現請求結果轉化,按上面那樣就可以了,使用工廠方法模式

  1. 繼承Converter,在convert方法中返回轉換后的結果,比如GsonRequestBodyConverter中是把ResponseBody轉成自己需要轉的類型。
  2. 繼承Converter.Factory,在responseBodyConverter中將相應的Converter對象返回。
  3. 在Retrofit的創造器中調用addConverterFactory添加相應的Converter.Factory。

2.3 build()

這部將根據先前的配置生成Retrofit,其實Builder中的配置屬性幾乎都賦值給了Retrofit。

public Retrofit build() {

    //callFactory是類okhttp3.Call.Factory的對象,如果自己沒有設置了OkHttp對象,則會自己創建一個。
  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

  //回調方法執行器
  Executor callbackExecutor = this.callbackExecutor;
  //沒有指定的話,就用構造器中賦值的platform中的,也就是將回調放在主線程
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  // 將配置的網絡適配器進行保護性拷貝
  List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  //添加默認的網絡適配器,也就是ExecutorCallAdapterFactory
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

  // 與網絡適配器的排序不同,默認的BuiltInConverters放在第一位,后面才是添加的
  List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

對于網絡適配器隊列存儲順序和數據轉化器的隊列順序不同,其實是在后面給ServiceMethod賦值相應屬性時,采取了不同的取值策略。網絡適配器優先獲取隊列前面的;數據轉化器雖然也是從隊列前面開始適配,但默認的BuiltInConverters要接口返回類型為ResponseBody或Void才會返回Converter對象,返回類型為其它時,會繼續遍歷后面的數據轉化器,所以在設定返回值為對象時,GsonConverterFactory會起作用。具體后面ServiceMethod創建時會介紹。

2.4 總結

在最后build()中,可以發現創建Retrofit時,傳入了6個參數。

  1. OKHttp對象。比如設置連接超時時間的OKHttp
  2. 服務器地址。必填
  3. 請求結果的數據轉換器。對于請求結果的返回類型進行轉換
  4. 網絡適配器。默認為ExecutorCallAdapterFactory,通常設置為RxJava2CallAdapterFactory.create()。
  5. 回調方法執行器。默認回調在主線程執行。
  6. 是否提前對業務接口中的注解進行驗證轉換的標志位。在create中有用到。

比較重要的類有設置默認回調方法執行器和默認網絡適配器的Platform;默認的數據轉換器BuiltInConverters。

三 通過Retrofit獲取接口對象

MovieService movieService = retrofit.create(MovieService.class);

public interface MovieService {
    //get請求
    @GET("top250")
    //網絡請求數據的方法,@Query配置請求參數
    Call<HttpResult<List<Subject>>> getTopMovie(@Query("start")int start, @Query("count")int count);
}

MovieService是個接口,里面定義了一個方法,通過注解上面配置了請求接口的參數配置,retrofit通過方法的參數創建接口對象。

那來看看如何通過接口來獲取對象。

3.1 create

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    //是否提前通過注解加驗證加載請求接口,會將接口中的方法都解析成ServiceMethod,并加入serviceMethodCache緩存中
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //創建動態代理對象,用來代理接口
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
    new InvocationHandler() {   //將代理類的實現交給 InvocationHandler類作為具體的實現
      private final Platform platform = Platform.get();

      //被代理執行的方法,是通過在InvocationHandler中的invoke方法調用的
      @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
          throws Throwable {
        // Object的方法直接調用原方法
        if (method.getDeclaringClass() == Object.class) {
          return method.invoke(this, args);
        }
        //android默認為false,不走
        if (platform.isDefaultMethod(method)) {
          return platform.invokeDefaultMethod(method, service, proxy, args);
        }
        
        //這里才是被代理方法真正執行的地方
        //通過接口方法的注解來獲取ServiceMethod
        ServiceMethod<Object, Object> serviceMethod =
            (ServiceMethod<Object, Object>) loadServiceMethod(method);
        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
        //如果是默認網絡適配器,就生成Call對象;RxJava則生成Observable對象
        return serviceMethod.callAdapter.adapt(okHttpCall);
      }
    });
}

代理模式的動態代理是實現接口方法調用的關鍵,動態代理也只能代理接口,invoke方法是接口方法正在實現的地方,生成的代理對象在運行時存在內存中。

這樣

那接下來看接口方法的調用。

四 通過接口對象獲取請求服務的Call對象

Call<HttpResult<List<Subject>>> call = movieService.getTopMovie(0, 10);

這里的getTopMovie方法調用,是在上面invoke方法中實現的,主要是這幾行代碼

//通過方法注解配置,獲取ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
    (ServiceMethod<Object, Object>) loadServiceMethod(method);
//根據ServiceMethod創建OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//創建Call
return serviceMethod.callAdapter.adapt(okHttpCall);

4.1 loadServiceMethod

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    //從緩存中獲取,如果先前創建過久直接用
    //create中的eagerlyValidateMethods方法會提前創建對象并緩存
    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()實現的。

4.1.1 new ServiceMethod.Builder<>(this, method)

Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  //獲取方法里的注解
  this.methodAnnotations = method.getAnnotations();
  //獲取方法的參數類型
  this.parameterTypes = method.getGenericParameterTypes();
  //獲取方法參數里的注解
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}

就是賦值。

4.1.2 build()

public ServiceMethod build() {
    //1.根據接口的返回類型和注解,從retrofit中獲取網絡適配器
    callAdapter = createCallAdapter();
    //方法返回值泛型的類型,也就是網絡請求的返回值類型
    responseType = callAdapter.responseType();
    
    //2.根據方法的返回類型和注解,網絡數據轉換器
    responseConverter = createResponseConverter();
    
    //3.獲取方法上的注解
    for (Annotation annotation : methodAnnotations) {
      //根據注解獲取配置
      parseMethodAnnotation(annotation);
    }
    
    //4.獲取方法參數里的注解
    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);
    }
    
    return new ServiceMethod<>(this);
}

重點關注下網絡適配器和數據轉換器是如何獲得的,根據前面的Builder可知,retrofit里它們都是以數組保存的,那獲取規則又如何呢。

4.1.2.1 createCallAdapter

先看網絡適配器如何獲取的。

private CallAdapter<T, R> createCallAdapter() {
    //返回值類型
  Type returnType = method.getGenericReturnType();
  //方法注解
  Annotation[] annotations = method.getAnnotations();
  try {
    //通過retrofit的callAdapter方法返回的
    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);
  }
}

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

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
      //從0開始
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      //在分析的例子中,沒有配置網絡適配器,所以用的默認的ExecutorCallAdapterFactory
      //使用RxJava會配置了RxJava2CallAdapterFactory
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
}

因為例子沒有配置網絡適配器
這里是使用默認的網絡適配器ExecutorCallAdapterFactory,如果配置了RxJava2CallAdapterFactory,它會在默認網絡適配器的前面,那時就會使用RxJava2CallAdapterFactory了。ExecutorCallAdapterFactory這個到后面通過網絡適配器返回的Call調用enqueue時再介紹。

4.1.2.2 createResponseConverter

解析的例子中,是配置了GsonConverterFactory數據轉換器。和上面的網絡適配器一樣,數據轉換器也是從retrofit保存的配置信息中獲取的

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    //從0開始
    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
    //默認的數據轉換器BuiltInConverters,如果接口方法返回值類型不是ResponseBody和Void的話,返回null
    //分析的這個例子中,接口方法返回值的泛型是HttpResult,所以會循環到下個GsonConverterFactor對象
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }

  }

數據轉換器把默認的BuiltInConverters放在了第一位,但還是根據接口方法返回值泛型會過濾選擇。所以在自定義轉換器時,要過濾要轉換的類型

4.2 ExecutorCallAdapterFactory

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
serviceMethod.callAdapter.adapt(okHttpCall)

又回到Retrofit中create的動態代理中來,到invoke中最后一步,返回Call。(如果是RxJava,則返回Observable)

根據上面的分析,可以知道serviceMethod.callAdapter對象是默認的ExecutorCallAdapterFactory。callAdapter和Converter都采用了工廠方法模式來實現,理解這個更有助于自定義它們。

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
//返回方法執行器
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }
  
  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //返回值類型判斷,要是Call才行
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    //返回值泛型的類型,如例子中的HttpResult
    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) {
        //相應的call對象
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };

  }
}

CallAdapter和它的工廠CallAdapter.Factory,是自定義CallAdapter的關鍵。

  • CallAdapter的adapt方法返回接口方法的返回值,上面是返回Call對象。如果是RxJava,則返回Observable對象。
  • CallAdapter.Factory則是創建CallAdapter的工廠,它的get方法返回CallAdapter對象
  • CallAdapter的adapt方法的返回對象,是實現后續網絡請求的關鍵,自定義要在返回對象中將自己封裝的網絡請求放在里面。

4.3 總結

到這里,如何通過接口對象調用方法獲取Call已經很明了了。就是通過動態代理對象里的InvocationHandler里的invoke方法實現,調用接口對象方法實際上是調用invoke方法。

在invoke中,首先根據接口方法的注解和Retrofit里的配置通過建造者模式生成ServiceMethod對象,再生成實現網絡請求的對象OkHttpCall,通過ServiceMethod中的CallAdapter來生成封裝了OkHttpCall的Call對象(RxJava則是Observable)。

自定義CallAdapter的關鍵是實現CallAdapter和CallAdapter.Factory。

五 請求網絡

請求網絡時通過調用call.enqueue,那來看看默認的Call對象相應方法的實現,也就是ExecutorCallAdapterFactory里的ExecutorCallbackCall

static final class ExecutorCallbackCall<T> implements Call<T> {
    //回調方法執行器
    final Executor callbackExecutor;
    //OkHttpCall對象,是生成ExecutorCallbackCall時傳入的
    final Call<T> delegate;

//在CallAdapter的adapt方法中被創建賦值
    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
    
    //代理模式,最終還是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()) {
              //失敗回調
               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);
            }
          });
        }
      });
    }
  }

ExecutorCallbackCall用的代理模式,最終實現的對象的OkHttpCall。

OkHttp的使用就分四步

  1. 創建okHttpClient對象
  2. 創建一個Request
  3. new call
  4. 請求加入調度

真正實現網絡請求的就是OKHttp,我們可以從上面四步了解網絡請求的實現。第一步在創建retrofit對象時就已經完成了。

5.1 OkHttpCall

OkHttpCall是retrofit2中封裝的一個類,內部調用還是通過ServiceMethod獲取網絡請求配置并生成okhttp3.Call來實現。

@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 {
        //1.生成okhttp3.Call對象,默認是OkHttpClient的newCall創建,為RealCall對象
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }
    //2.發送異步網絡請求
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
        //3.通過存在serviceMethod的Converter轉換數據類型
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        //4.回調接口
        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();
        }
      }
    });
  }

可以看出實現網絡請求的是OKhttp,那只要關注okhttp3.Call是如何創建和網絡請求結果如何轉換就好了。

5.1.1 createRawCall()

okhttp3.Call的創建就完成了OkHttp使用的前三步了,下面來看看前三部是怎么實現的吧。

所有的網絡配置信息都在ServiceMethod中,很明顯,它們的生成也都在ServiceMethod中,通過默認的OkHttpClient的newCall創建,為RealCall對象,這些還是后面看OKHttp的解析了解吧。

private okhttp3.Call createRawCall() throws IOException {
    //創建Request對象,將請求網絡的信息都封裝在里面
    Request request = serviceMethod.toRequest(args);
    //callFactory是okhttp3.Call.Factory,在創建Retrofit時默認的OkHttpClient
    //正常OKhttp生成Call的流程
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

創建Request,再創建okhttp3.Call,這是正常的OkHttp請求的第二三步。這里只關心Retrofit的封裝,就看toRequest方法了。

5.1.1.1 serviceMethod.toRequest

Request toRequest(@Nullable Object... args) throws IOException {
    //創造者模式構建對象
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    //接口方法的參數的注解結合
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    //校驗接口方法的參數的注解數量和接口方法參數的數量是否一致
    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }
    //對接口方法參數,會在apply中轉換參數類型,并添加到requestBuilder中。
    //數據轉換默認使用BuiltInConverters.ToStringConverter.INSTANCE,也就是直接將參數值toString()
    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }
    //里面通過參數,用普通的OKhttp的建造器生成Request
    return requestBuilder.build();
  }
  
  //例子中,添加的請求參數是Query,所以上面handlers[p].apply的實現是
  static final class Query<T> extends ParameterHandler<T> {

    @Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
      if (value == null) return; // Skip null values.
    //這里就是把value.toString()了
      String queryValue = valueConverter.convert(value);
      if (queryValue == null) return; // Skip converted but null values
    //添加到請求url里去
      builder.addQueryParam(name, queryValue, encoded);
    }
  }

對于接口方法注解的解析,我就不做太多介紹了。handlers[p].apply是將方法參數的配置信息添加到requestBuilder中去,將參數配置都添加后,在build中,用OKhttp的Request.Builder生成Request對象。

RequestBuilder將baseUrl和請求接口方法里的注解配置信息組合起來,將配置信息添加入Request.Builder中,創建Request。

5.2 parseResponse

call.enqueue這個方法是okhttp3.Call的方法,就不分析了,主要分析請求服務結束后,將數據類型轉換為回調接口需要的類型。

 Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // 移除Response中的響應正文,在此基礎上創建一個新的Response
    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);
      //將轉換后內容和空body的Response再組合成Retrofit里的Response
      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;
    }
  }

這里將okhttp3.Response,將響應正文通過數據轉換器轉換,再和空響應正文的okhttp3.Response組合成Retrofit里的Response,用于回調使用。

callback.onResponse是回調了默認網絡適配器里的ExecutorCallbackCall里的Callback,然后ExecutorCallbackCall里再使用默認的Executor在主線程回調例子里的Callback。

六 總結

  1. Converter和CallAdapter都是用工廠方法模式實現的,自定義時要分別實現產品類和工廠類,在工廠類中創建產品。
  2. Retrofit是通過建造者模式創建的,Retrofit.Builder()主要配置:網絡請求工廠(okhttp3.Call.Factory),網絡請求地址(HttpUrl),數據轉換器(List<Converter.Factory>),網絡適配器(List<CallAdapter.Factory>),回調執行方法(Executor),是否提前對業務接口中的注解進行驗證轉換的標志位(validateEagerly)
  3. 接口方法里通過注解配置了網絡請求的配置,通過Retrofit的create方法,動態代理實現了接口方法。接口方法的返回值是網絡適配器返回對象,類型要和接口方法的返回值一致。
  4. 動態代理的invoke方法里,通過Retrofit的配置和接口方法的注解配置生成ServiceMethod對象,這個對象保存了網絡請求的所有配置。大部分方法和解析注解生成配置有關,主要關注兩個方法:一個toRequest通過RequestBuilder生成OKhttp的Request,toResponse可以利用數據轉換器將ResponseBody轉為請求接口方法返回值泛型。這兩個方法都是給OkHttpCall使用。
  5. 再通過ServiceMethod創建了OkHttpCall,里面有請求網絡的方法,實際上是根據ServiceMethod的配置網絡信息生成的Request再生成okhttp3.Call,將請求結果通過ServiceMethod的配置轉換器進行數據轉換,最終回調給調用它的類(默認ExecutorCallbackCall)。
  6. ExecutorCallAdapterFactory是默認的網絡適配器工廠,在動態代理的invoke方法里,創建ServiceMethod時用get方法生成適配器后,再通過適配器的adapt生成ExecutorCallbackCall返回值,ExecutorCallbackCall中用靜態代理模式實現,被代理對象是OkHttpCall。
  7. GsonConverterFactory的具體轉換結果類型,是在創建ServiceMethod時,用解析的接口方法中的返回值泛型確定的。
  8. 隨后再列下關鍵的幾個類:
  • Retrofit:用創建者模式存儲網絡配置。
  • ServiceMethod:通過接口方法注解的配置和Retrofit里的配置,生成ServiceMethod。toReques和toResponse方法供給OkHttpCall使用。
  • ServiceMethod中利用RequestBuilder,生成Request請求。Request利用Retrofit配置的網絡參數,和ServiceMethod里解析接口方法里的注解配置,生成Request請。
  • OkHttpCall:網絡請求的封裝類,內部結合ServiceMethod的toReques生成OKHttp實現網絡請求,再用ServiceMethod的toResponse轉換結果回調給調用它的對象,這個對象是網絡適配器adapt生成。

參考

Android OkHttp完全解析 是時候來了解OkHttp了

你真的會用Retrofit2嗎?Retrofit2完全教程

Android:手把手帶你 深入讀懂 Retrofit 2.0 源碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容