經常使用輪子之Retrofit基本使用及原理

不忘初心 砥礪前行, Tomorrow Is Another Day !java

相關文章

本文概要:設計模式

  1. 引言
    • okHttp、urlConnection、httpClient、volley、retrofit之間的關係
  2. Retrofit的使用-簡單介紹
  3. Retrofit的原理-重點分析

一. 引言

在分析Retrofit以前,咱們須要對基本的網絡以及網絡框架有個綜合的對比認識.api

okHttp、urlConnection、httpClient、volley、retrofit之間的關係緩存

  • okHttp、urlConnection、httpClient 這三者是底層的網絡庫.
  • volley與retrofit屬於更高層的網絡庫
  • volley對urlConnection和httpClient的進行了封裝,因爲volley良好的擴展性,它還能配置使用okHttp做爲底層庫
  • retrofit則是在okhttp的基礎上封裝了線程的切換及網絡數據解析

二. Retrofit的使用

Retrofit的使用比較簡單,基本是就是經過三類註解方法註解,參數註解. 這裏就再也不講述了,找了一篇我的感受比較全面的文章你真的會用Retrofit2嗎?Retrofit2徹底教程進行參考學習.咱們重點進行原理分析.bash

三. 基本原理

3.1 Retrofit的建立

源碼版本2.5.0
Retrofit是經過動態代理的方式建立各類網絡接口的代理.網絡

關於動態代理,筆者另起了篇講述.設計模式之代理模式若有興趣的能夠看一下.最後咱們迴歸正題.框架

使用過程通常都是經過建造者的build方法來構建Retorfit對象.咱們就從Retorfit對象的建立開始,異步

使用示例-1ide

mRetrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .callFactory(okHttpClient)
                .build();
複製代碼

直接看build方法的對應源碼oop

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

      // 1.初始化callFactory,若是未設置則默認設置一個OkHttpClient

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      // 2.初始化回調執行器,用於回調到UI線程
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // 3.初始化適配器工廠集合,添加一個默認適配器工廠(ExecutorCallAdapterFactory)
      //用於適配返回類型,如默認支持的Call<T>
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // 4.初始化轉換器集合
      //用於網絡響應的解析
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      //...省略部分代碼

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  
複製代碼

在build方法裏,初始化時會經過platform對象添加一些默認的適配器,轉換器,以及回調執行器.咱們看具體的添加操做.

對應源碼

static class Android extends Platform {
    @IgnoreJRERequirement // Guarded by API check.
    @Override boolean isDefaultMethod(Method method) {
      if (Build.VERSION.SDK_INT < 24) {
        return false;
      }
      return method.isDefault();
    }
    //添加默認回調執行器
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    //添加默認的適配器工廠(ExecutorCallAdapterFactory)
    @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }

    @Override int defaultCallAdapterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
    }

    //添加默認的轉換器工廠
    @Override List<? extends Converter.Factory> defaultConverterFactories() {
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }

    @Override int defaultConverterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
    }

    static class MainThreadExecutor implements Executor {
      //綁定主線程的looper
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        //回調到主線程執行
        handler.post(r);
      }
    }
  }
複製代碼

至此Retorfit對象建立過程就分析完了,作一個小結.

對於Retorfit的建立,進行一系列的初始化操做.

  • 初始化callFactory
  • 初始化"三器"
    • 回調執行器,用於回調到UI線程
    • 適配器工廠,用於適配返回的類型
    • 轉換器工廠,用於解析網絡響應

3.2 Call的建立

Call的建立過程實質是網絡接口的實現過程

Rerofit對象建立完成後,調用create方法時來實現咱們定義的網絡接口ApiService,採用的就是動態代理.

使用示例-2

定義的網絡接口類
public interface ApiService{
    @GET
    Observable<IDocViewBean> oaFileUpload(@Url String url,
                                          @Query("token") String token,
                                          @Query("mode") String mode,
                                          @Query("url") String urlFile);
}

ApiService apiService = retrofit.create(ApiService.class);
複製代碼

對應源碼

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    /*
     * 返回了網絡接口的代理對象
     */
    //當咱們調用代理對象的接口方法時,會觸發InvocationHandler的invoke方法.
    //如調用apiService.oaFileUpload(...)時,會完成oaFileUpload的實現,並返回一個Call<T>
    //如調用apiService.oaFileUpload(...)時,會完成oaFileUpload的實現,並返回一個Call<T>
    //如調用apiService.oaFileUpload(...)時,會完成oaFileUpload的實現,並返回一個Call<T>
    //重要話說三遍,這一句理解了後面就容易了.
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @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);
            }
            //加載網絡接口的方法,如加載oaFileUpload方法並調用.
             /**
             * 第一大步:先分析loadServiceMethod(method)獲取到網絡接口方法對象(ServiceMethod對象)
             * 第二大步:調用ServiceMethod的invoke.
             */
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

    
複製代碼

3.2.1 第一大步

接着咱們看loadServiceMethod的具體實現

對應源碼

ServiceMethod<?> loadServiceMethod(Method method) {
    //先從緩存中獲取.
    ServiceMethod<?> result = serviceMethodCache.get(method);
    //有緩存,直接返回.
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        //無緩存,對網絡接口的方法進行解析,封裝成ServiceMethod並添加進緩存.
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
複製代碼

對網絡接口的方法進行解析調用的了ServiceMethod.parseAnnotations,實際調用的是它的子類HttpServiceMethod.parseAnnotations方法.這裏咱們直接看子類的方法.

對應源碼

//HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    //建立CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();
    if (responseType == Response.class || responseType == okhttp3.Response.class) {
      throw methodError(method, "'"
          + Utils.getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }
    //建立轉換器
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
  }
  
  
  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();
    Annotation[] annotations = method.getAnnotations();
    try {
      //noinspection unchecked
      //裏面經過retrofit對象的callAdapter方法獲取CallAdapter對象
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
  }
複製代碼

createCallAdapter方法調用了retrofit對象的callAdapter方法獲取CallAdapter對象.接着看retrofit的CallAdapter方法.

對應源碼

//retrofit.java
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    //再接着往下看
    return nextCallAdapter(null, returnType, annotations);
  }
  
  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;
    //先遍歷callAdapterFactories集合
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      //再經過網絡接口的返回類型(returnType)來獲取適配器工廠(CallAdapter.Factory),最終獲取到CallAdapter對象.
      //再經過網絡接口的返回類型(returnType)來獲取適配器工廠(CallAdapter.Factory),最終獲取到CallAdapter對象.
      //再經過網絡接口的返回類型(returnType)來獲取適配器工廠(CallAdapter.Factory),最終獲取到CallAdapter對象.
      //重要的話說三遍.
      //因爲以前在Retrofit對象建立階段時,有默認設置CallAdapter.Factory爲ExecutorCallAdapterFactory,那麼遍歷時就會獲取到它.
      //最後一塊兒看下ExecutorCallAdapterFactory的get方法.
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    
複製代碼
//ExecutorCallAdapterFactory.java
@Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //檢測返回類型是否是CALL
    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;
      }


     //...省略部分代碼
    };
  }
複製代碼

3.2.2 第二大步

調用ServiceMethod實際調用了HttpServiceMethod的invoke方法,咱們直接看這個方法.

//HttpServiceMethod.java
@Override ReturnT invoke(Object[] args) {
    /*由於以前第一大步咱們已經清楚,默認狀況下callAdapter是ExecutorCallAdapterFactory適配器工廠下返回的,
    那麼繼續往下看適配器工廠找adapt
    */
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }
  
  //ExecutorCallAdapterFactory.java
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
     //...省略部分代碼

      @Override
      public Call<Object> adapt(Call<Object> call) {
        //返回的Call實際上就是ExecutorCallbackCall
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
複製代碼

Call的建立過程相對來講比較複雜,須要反覆多瀏覽幾遍,關鍵在於冷靜下來根據線索去尋找.最後對Call的建立過程作一個總結.

  • 當調用代理對象的網絡接口方法時,會觸發InvocationHandler的invoke方法,最終返回一個Call.
  • 在invoke方法裏面主要包含兩大步驟.
    1. 第一大步,獲取到網絡接口方法對象(loadServiceMethod)
      • 檢查是否有緩存,有直接返回,無,從新解析生成新的對象後,緩存再返回
        • 解析時獲取適配器(CallAdapter),遍歷適配器工廠集合,經過網絡接口的返回類型(returnType)來獲取對應適配器工廠,最終得到適配器(CallAdapter).
    2. 第二大步,調用ServiceMethod的invoke發送請求.
      • 一樣利用獲取到的CallAdapter調用adapt方法,返回一個Call對象.最後發送請求.

3.3 網絡請求的發送過程

最後咱們看ExecutorCallbackCall是如何發請求和回調的.

對應源碼

static final class ExecutorCallbackCall<T> implements Call<T> {
    //初始化時設置的線程回調執行器
    final Executor callbackExecutor;
    //爲OkHttpCall
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    
  //發送網絡請求
    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

      delegate.enqueue(new Callback<T>() {//使用okhttpClient進行異步請求
        //網絡回調成功
        @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);
            }
          });
        }
      });
    }

    //...省略部分代碼
}
複製代碼

最後老規矩,對網絡請求的發送過程作一個小結.

經過enqueue方法,利用Okhttp發送網絡請求,網絡響應成功或失敗經過回調執行器(MainThreadExecutor)分發到主線程執行.


因爲本人技術有限,若有錯誤的地方,麻煩你們給我提出來,本人不勝感激,你們一塊兒學習進步.

相關文章
相關標籤/搜索