Android網絡編程(十二) 之 Retrofit2原理分析

1 使用回顧

我們在前面博文《Android網絡編程(十一) 之 Retrofit2框架的使用》中已經對Retrofit的使用進行過介紹。今天我們接着往下來閱讀Retrofit的關鍵源碼從而它進行更加深入的理解。開始前,先來回顧一下簡單的使用,通過使用步驟來深入分析每行代碼背後的原理,代碼如:

    // 0 創建一個網絡請求的接口
    public interface AppInfoService {
        @GET("url.json")
        Call<List<AppInfo>> getAppInfoList(@Query("id") int id);
    }

    private void getRequest() {
        // 1 創建 Retrofit 對象,輸入請求URL、轉換器等
        Retrofit retorfit = new Retrofit.Builder()
                .baseUrl("https://api.xx.com/ ")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2 通過Retrofit的create創建自定義的請求接口對象
        AppInfoService appInfoService = retorfit.create(AppInfoService.class);
        // 3 通過調用請求接口方法創建Call對象
        Call<List<AppInfo>> call = appInfoService.getAppInfoList(123);
        // 4 發起同步或異步的網絡請求
//        try {
//            Response<List<AppInfo>> response = call.execute();
//            List<AppInfo> appInfos = response.body();
//            Log.e("zyx", appInfos.toString());
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        call.enqueue(new Callback<List<AppInfo>>() {
            @Override
            public void onResponse(Call<List<AppInfo>> call, Response<List<AppInfo>> response) {
                List<AppInfo> appInfos = response.body();
                Log.e("zyx", appInfos.toString());
            }

            @Override
            public void onFailure(Call<List<AppInfo>> call, Throwable t) {
                Log.e("zyx", t.toString());
            }
        });
    }

可見其步驟大概是:

0 創建一個自定義的網絡請求的接口,裏頭包含請求方式、請求服務端接口名和請求參數的傳入的方法;

1 創建 Retrofit 對象,輸入請求URL、轉換器等;

2 通過Retrofit的create創建自定義的請求接口對象;

3 通過調用請求接口方法創建Call對象;

4 發起同步或異步的網絡請求。

2 原理分析

2.1 創建Retrofit對象

Retrofit對象的創建過程也是使用了構造器模式進行的初始化。首先,Builder方法最終會調用到Platform類的findPlatform方法。

Retrofit.java

public static final class Builder {
  // ……
  Builder(Platform platform) {
    this.platform = platform;
  }

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

Platform.java

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  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方法內部會根據不同的運行平臺來創建不同的Platform對象。接着調用其build方法。

Retrofit.java

public final class Retrofit {
public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;

    // ……

    public Retrofit build() {
// 關鍵代碼1,判斷baseUrl是否爲空
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      // 關鍵代碼2,獲得或創建 網絡請求執行器工廠 okhttp3.Call.Factory對象
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      // 關鍵代碼3,獲得或創建回調方法執行器Executor對象
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

// 關鍵代碼4,創建 網絡請求適配器工廠CallAdapter.Factory列表,
// 並將callAdapterFactories和上面的callbackExecutor對象創建出默認的defaultCallAdapterFactories添加其中
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

// 關鍵代碼5,創建 數據轉換器工廠Converter.Factory列表
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size() + latform.defaultConverterFactoriesSize());
      // 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());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());
      // 關鍵代碼6,實例化Retrofit對象
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  }
}

Build方法裏邏輯很清晰,主要就是5件事情:

  1. 判斷baseurl是否爲空,baseurl的值就是通過. baseUrl方法進行設置。
  2. 獲得網絡請求執行器工廠callFactory對象值,若爲空,則創建一個OkHttpClient對象,所以很明顯Retrofit默認使用OkHttp進行網絡請求,callFactory的值可通過. client方法進行設置。
  3. 獲得回調方法執行器callbackExecutor對象值,若爲空,則創建一個默認的,該默認的是一個MainThreadExecutor對象且它內部有一個帶有Looper的Handler,我們後面再來討論它。callbackExecutor的值可通過. callbackExecutor方法進行設置。
  4. 獲得網絡請求適配器工廠callAdapterFactories的值,將其添加到列表中,callAdapterFactories的值可通過. addCallAdapterFactory方法進行設置。列表創建完後再將關鍵代碼3中的callbackExecutor對象添加其中。
  5. 創建一個數據轉換器工廠Converter.Factory列表,之後添加內置的數據轉換器BuiltInConverters和默認的數據轉換器工廠defaultConverterFactories,其中還獲得converterFactories的值,也將其添加到列表中,converterFactories的值可通過. addConverterFactory方法進行添加。
  6. 最後將上述對象傳入Retrofit的構造函數中去實例化Retrofit對象,注意validateEagerly值表示提前驗證,可通過. validateEagerly方法進行設置。

2.2通過Retrofit的create創建自定義的請求接口對象

如示例中代碼 AppInfoService appInfoService = retorfit.create(AppInfoService.class);,Retrofit的create方法是一個泛型的方法,參數就是自定義的接口類型,返回值是一個Proxy.newProxyInstance動態代理對象,請看代碼。

Retrofit.java

public final class Retrofit {
  // ……
  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
// 關鍵代碼1,是否提前驗證
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
// 關鍵代碼2,創建一個用於網絡請求接口的動態代理對象並返回 
    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 @Nullable 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);
            }
// 關鍵代碼3,加載網絡請求接口裏的方法,並執行
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        loadServiceMethod(method);
      }
    }
  }
  // ……
}
  1. create方法內首先會判斷validateEagerly變量是否爲true,即是否提前驗證,eagerlyValidateMethods方法其實也就是提前去觸發關鍵代碼3中loadServiceMethod方法邏輯。
  2. 關鍵代碼2處,此處是創建了一個用於網絡請求接口的動態代理對象,也就是當我們去調用使用回調示例中的AppInfoService的getAppInfoList方法時,最終會調用InvocationHandler的invoke方法。
  3. 關鍵代碼3處,是加載網絡請求的接口裏的方法並執行,method就是我們自定義的getAppInfoList方法。

2.3通過調用請求接口方法創建Call對象

如示例中代碼Call<List<AppInfo>> call = appInfoService.getAppInfoList(123);,該方法返回一個Call對象,從2.2中得知該方法最終會調用到Retrofit的loadServiceMethod方法返回對象的invoke方法中去,所以我們繼續來看loadServiceMethod方法和invoke方法的代碼。

2.3.1 loadServiceMethod方法

Retrofit.java

public final class Retrofit {
  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) {
// 關鍵代碼
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
// ……
}

loadServiceMethod方法內先從靜態Map對象serviceMethodCache中讀取是否存在之前創建過的網絡請求實例,如果有就直接返回。否則通過ServiceMethod.parseAnnotations方法創建再添加到serviceMethodCache中去最後返回新創建對象。

ServiceMethod.java

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 關鍵代碼1,創建一個請求工廠RequestFactory對象
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

// 關鍵代碼2,創建HttpServiceMethod對象並返回
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

方法就是做了兩件事情:

  1. 通過RequestFactory類的parseAnnotations方法創建一個請求工廠。
  2. 最終創建一個HttpServiceMethod對象並返回。

下面我們繼續來分析RequestFactory的parseAnnotations方法和HttpServiceMethod的parseAnnotations方法邏輯。

2.3.1.1RequestFactory的parseAnnotations方法

RequestFactory.java

final class RequestFactory {
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

  private final Method method;
  private final HttpUrl baseUrl;
  final String httpMethod;
  private final @Nullable String relativeUrl;
  private final @Nullable Headers headers;
  private final @Nullable MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;
  final boolean isKotlinSuspendFunction;

  RequestFactory(Builder builder) {
    method = builder.method;
    baseUrl = builder.retrofit.baseUrl;
    httpMethod = builder.httpMethod;
    relativeUrl = builder.relativeUrl;
    headers = builder.headers;
    contentType = builder.contentType;
    hasBody = builder.hasBody;
    isFormEncoded = builder.isFormEncoded;
    isMultipart = builder.isMultipart;
    parameterHandlers = builder.parameterHandlers;
    isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
  }
// ……
  static final class Builder {
    // ……
    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

    RequestFactory build() {
      // ……
      return new RequestFactory(this);
    }
private void parseMethodAnnotation(Annotation annotation) {
    if (annotation instanceof DELETE) {
      parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
    } else if (annotation instanceof GET) {
      parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    } else if (annotation instanceof HEAD) {
      parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
    } else if (annotation instanceof PATCH) {
      parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
    } else if (annotation instanceof POST) {
      parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
    } else if (annotation instanceof PUT) {
      parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
    } else if (annotation instanceof OPTIONS) {
      parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
    } else if (annotation instanceof HTTP) {
      HTTP http = (HTTP) annotation;
      parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
    } else if (annotation instanceof retrofit2.http.Headers) {
      String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
      if (headersToParse.length == 0) {
        throw methodError(method, "@Headers annotation is empty.");
      }
      headers = parseHeaders(headersToParse);
    } else if (annotation instanceof Multipart) {
      if (isFormEncoded) {
        throw methodError(method, "Only one encoding annotation is allowed.");
      }
      isMultipart = true;
    } else if (annotation instanceof FormUrlEncoded) {
      if (isMultipart) {
        throw methodError(method, "Only one encoding annotation is allowed.");
      }
      isFormEncoded = true;
    }
  }
// ……
}

可見RequestFactory的parseAnnotations方法其實就是傳入Retrofit對象和method參數,然後通過讀取method中定義的註解值(類中的parseMethodAnnotation方法),得到各種網絡請求參數的一個對象。

2.3.1.2 HttpServiceMethod的parseAnnotations方法

獲得RequestFactory對象後,就是作爲參數傳到HttpServiceMethod的parseAnnotations方法去,再看代碼。

HttpServiceMethod.java

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // ……
// 關鍵代碼1,從Retrofit對象中的 網絡請求適配器工廠 獲得 網絡請求適配器callAdapter和其請求類型
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(method, "'" + getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }

// 關鍵代碼2,從Retrofit對象中的 數據轉換器工廠 獲得 數據轉換器 responseConverter
    Converter<ResponseBody, ResponseT> responseConverter =  createResponseConverter(retrofit, method, responseType);

// 關鍵代碼3,從Retrofit對象中的 獲得 網絡請求執行器工廠 callFactory
    okhttp3.Call.Factory callFactory = retrofit.callFactory;

// 關鍵代碼4,根據類型創建不同的HttpServiceMethod實現
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
    }
  }
  // ……
}

HttpServiceMethod的parseAnnotations方法裏會去獲取之前在Retrofit對象中的 網絡請求適配器callAdapter、數據轉換器responseConverter、網絡請求執行器工廠callFactory 以及 通過參數傳入的請求工廠RequestFactory作爲參數,去根據不同類型創建三種分別是CallAdapted,SuspendForResponse和SuspendForBody的HttpServiceMethod對象。其中SuspendForResponse和SuspendForBody是Kotlin suspend 方法的支持,所以我們只看CallAdapted便可以了。

HttpServiceMethod.java

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  private final CallAdapter<ResponseT, ReturnT> callAdapter;

  CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
      Converter<ResponseBody, ResponseT> responseConverter,
      CallAdapter<ResponseT, ReturnT> callAdapter) {
    super(requestFactory, callFactory, responseConverter);
    this.callAdapter = callAdapter;
  }

  @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
  }
}

 2.3.2 invoke方法

看回上面的 return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); 代碼,當loadServiceMethod方法返回了ServiceMethod對象後,接着就是調用它的invoke方法。

ServiceMethod.java

abstract class ServiceMethod<T> {
  // ……
  abstract @Nullable T invoke(Object[] args);
}

invoke方法的實現在HttpServiceMethod類中。

HttpServiceMethod.java

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
// ……
@Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
  protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
}

Invoke方法很簡單,就是調用adapt方法,也就是HttpServiceMethod的實現類CallAdapted中的adapt方法。其代碼已經在上面貼過。這裏請記住第一個參數call是OkHttpCall。

HttpServiceMethod.java

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  //……
  @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
  }
}

最終就是 網絡請求適配器callAdapter的adapt方法。

這個網絡請求適配器callAdapter就是在HttpServiceMethod的parseAnnotations方法中關鍵代碼1中,從Retrofit對象中的 網絡請求適配器工廠 獲得的 網絡請求適配器callAdapter。回顧一下上面創建Retrofit對象中的 網絡請求適配器工廠,當時提到該 網絡請求適配器工廠callAdapterFactories的值可通過. addCallAdapterFactory方法進行設置 和 默認的defaultCallAdapterFactories

Platform.java

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {
  return singletonList(new DefaultCallAdapterFactory(callbackExecutor));
}
DefaultCallAdapterFactory.java
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;

  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
    final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }
}

最終,如果我們沒有通過. addCallAdapterFactory方法指定callAdapter的話,invoke方法會執行到DefaultCallAdapterFactory類中,所以創建Call對象就是ExecutorCallbackCall對象。

DefaultCallAdapterFactory的ExecutorCallbackCall構造方法接收兩個參數。先說說第二個參數call,我們在HttpServiceMethod的invoke中可知是一個OkHttpCall對象。而第一個參數executor是在創建Retrofit對象時的回調方法執行器callbackExecutor,如果當時不通過.callbackExecutor方法設置的話,它默認是platform.defaultCallbackExecutor();,一個MainThreadExecutor對象,它的源碼如下,可見它內部有一個帶有Looper的Handler。

Platform.java

class Platform {
  // ……
  static class Android extends Platform {
    // ……
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
// ……
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

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

2.4發起網絡請求

獲得Call對象後就是最後發請網絡請求。從上面我們得知Call對象就是DefaultCallAdapterFactory.ExecutorCallbackCall,所以無論是異步還是同步的請求,都是調用了DefaultCallAdapterFactory.ExecutorCallbackCall裏的enqueue和execute方法。源碼如下。

DefaultCallAdapterFactory.java

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  // ……
  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;
    }

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

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

@Override public Response<T> execute() throws IOException {
      return delegate.execute();
    }
// ……
}

enqueue和execute方法內都是代理了delegate對象執行,而delegate對象就是OkHttpCall對象。所以我們只看OkHttpCall的enqueue邏輯就會明白了。

OkHttpCall.java

final class OkHttpCall<T> implements Call<T> {
  // ……
  @Override public void enqueue(final Callback<T> callback) {
    // ……
    okhttp3.Call call;
    // ……
      if (call == null && failure == null) {
        try {
// 關鍵代碼1,創建okhttp3的call對象
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          // ……
        }
      }
    }
    // ……
// 關鍵代碼2,執行call對象的異常請求
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
// 關鍵代碼3,獲得請求結果進行解析
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }
      // ……
    });
  }
  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
}

關鍵代碼1中通過createRawCall方法創建了一個okhttp3的call對象,接着在關鍵代碼2中去執行okhttp3的異常請求,然後在關鍵代碼3中通過parseResponse方法進行了請求結果的解析和封裝。最後結果再回調到ExecutorCallbackCall中去,而我們知道okhttp3的回調是執行在子線程中的,在ExecutorCallbackCall也就是MainThreadExecutor對象,因爲它本身帶有Looper的Handler,所以最終將結果回調到主線程中去執行。

同理,同步的方法execute也是調用了okhttp3的call對象的execute方法,最終也是通過parseResponse方法進行了請求結果的解析和封裝。

3 總結

至此,關於Retrofit2框架就介紹完畢,雖然過程中省略了大量的細節,但整體過程原理還是通過源碼瞭解很多。那我們現在用簡短的話來總結一下原理:

1創建Retrofit對象,內部先會根據不同的運行平臺來創建不同的Platform對象。然後通過構造器模式進行參數的初始化,如使用:

  1. 使用baseUrl方法設置要訪問的URL;
  2. 選擇性使用callFactory方法創建“網絡請求執行器工廠”callFactory,若不使用該方法,則會創建一個OkHttpClient對象;
  3. 選擇性使用callbackExecutor方法創建“回調方法執行器”callbackExecutor,若不使用該方法,則創建一個默認的defaultCallbackExecutor,它是一個帶Looper的Handler的MainThreadExecutor對象;
  4. 選擇性使用addCallAdapterFactory方法添加“網絡請求適配器工廠”,以及追加一個默認的網絡請求器DefaultCallAdapterFactory;
  5. 選擇性使用addConverterFactory方法添加“數據轉換器工廠”中;
  6. 最後通過上述創建的對象進行實例化Retrofit。

2通過Retrofit的泛型方法create並會傳入自定義的接口類型來創建自定義的請求接口對象,該對象是使用了Proxy.newProxyInstance的動態代理對象。

3通過調用自定義的請求接口方法創建Call對象,

  1. 內部先獲取定義方法中的註解值創建一個“請求工廠”RequestFactory,然後再獲取前面Retrofit對象中的“網絡請求適配器”callAdapter、“數據轉換器”responseConverter、“網絡請求執行器工廠”callFactory 以及 剛創建的“請求工廠”RequestFactory,根據類型創建出繼承於HttpServiceMethod的CallAdapted對象;
  2. 因爲使用了動態代理,所以最後會調用到CallAdapted對象的adapt方法去,又因爲默認的“網絡請求適配器”就是DefaultCallAdapterFactory對象,所以最後adapt方法內部創建的Call對象就是ExecutorCallbackCall對象。

4發起網絡請求,就是通過DefaultCallAdapterFactory.ExecutorCallbackCall的enqueue和execute方法來執行異步和同步。這兩個方法都是通過一個OkHttpCall對象來完成,OkHttpCall內部就是封裝了okhttp3的網絡請求。待請求完成後更是將結果回調回到ExecutorCallbackCall裏,再通過帶Looper的Handler的MainThreadExecutor回調方法執行器將結果回調到調用方的主線程中去。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章