RxJava + Retrofit原始碼解析

妖久發表於2022-04-24

RxJava + Retrofit怎麼請求網路,具體的用法這裡就不講了,本文只講一些重點原始碼。

版本如下:

okhttp                         : "com.squareup.okhttp3:okhttp:3.10.0",
okhttp3_integration            : "com.github.bumptech.glide:okhttp3-integration:1.4.0@aar",
retrofit                       : "com.squareup.retrofit2:retrofit:2.4.0",
converter_gson                 : "com.squareup.retrofit2:converter-gson:2.3.0",
converter_scalars              : "com.squareup.retrofit2:converter-scalars:2.3.0",
converter_protobuf             : "com.squareup.retrofit2:converter-protobuf:2.3.0",
adapter_rxjava2                : "com.squareup.retrofit2:adapter-rxjava2:2.2.0",
logging_interceptor            : "com.squareup.okhttp3:logging-interceptor:3.10.0",
rxjava                         : "io.reactivex.rxjava2:rxjava:2.1.12",
rxandroid                      : "io.reactivex.rxjava2:rxandroid:2.0.2",

一、首先關於Retrofit的初始化:

private void initRetrofit() {
    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
    retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl) //設定地址
            .client(client.build()) //設定自定義的OkHttpClient
            .addConverterFactory(ProtoConverterFactory.createWithRegistry(extensionRegistry))
            .addConverterFactory(StringConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(buildGson()))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();
    service = retrofit.create(ApiService.class);
}
.addConverterFactory(ProtoConverterFactory.createWithRegistry(extensionRegistry))
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(buildGson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

新增了資料轉換器與請求介面卡。

Retrofit的初始化採用了Builder模式。

Retrofit.Builder()這一步,獲取了一個平臺,肯定就是Android()了,後面有地方會用到。

Builder(Platform platform) {
  this.platform = platform;
}
public Builder() {
  this(Platform.get());
}
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();
  }
}

在看最後的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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories =
      new ArrayList<>(1 + this.converterFactories.size());
  // 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);
  return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

1、如果沒有傳入我們自定義的OkHttpClient,那麼便會使用預設的。

2、如果沒有設定自定義的回撥執行器,那麼便會是用預設的platform.defaultCallbackExecutor();點進入可以發現回撥是預設在主執行緒中的:

static class Android extends Platform {
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }
  @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    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);
    }
  }
}

3、把我們設定的請求介面卡新增進入,然後再新增一個預設的請求介面卡。

4、新增進入一個預設的資料轉換器,然後再被我們設定的資料轉換器新增進去。

 

二、初始化好Retrofit後,再來看這一句:

service = retrofit.create(ApiService.class);

ApiService是一個介面,裡面方法如下:

@GET
Observable<ResponseBody> doGet(@Url String url, @HeaderMap Map<String, String> headers, @QueryMap Map<String, String> map);

這個create方法可以說是核心,它運用的是動態代理。

@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.adapt(okHttpCall);
        }
      });
}

1、首先檢測這是否是一個介面,只有介面才能對它進行動態代理。

2、是否需要對介面裡面的方法進行初始化預載入,是的話便進行,這個與下面的有點重複,直接講下面的。

3、return後面的語句便是動態代理的地方,它會代理介面的所有方法,也就是說,當我們呼叫ApiService的方法的時候,會被攔截,然後走到inoke這個方法做我們自己的操作。

關於動態代理,後面會單獨講。

4、接下來邊看invoke方法:

(1)、首先判斷該方法是否為Object這個類的方法,如果是,不攔截它,讓他走原來的方法。

(2)、platform為Android,platform.isDefaultMethod(method)返回false,不用管它。

(3)、ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);拿到介面的方法,對介面的方法進行解析,比如獲取註解,引數之類,構造自己的serviceMethod 

(4)、初始化OkHttpCall

(5)、呼叫serviceMethod.adapt(okHttpCall)進行請求(因為採用的是RxJava,所以這裡並不會立即請求,只有被訂閱的時候才會,等會會講)

 

三、loadServiceMethod(method)方法:

構造自己的serviceMethod 也採用了Builder模式。

進入這個方法後,重點的一句:

result = new ServiceMethod.Builder<>(this, method).build();

先看:

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

注:我們這裡以前面定義的方法來講解:

@GET
Observable<ResponseBody> doGet(@Url String url, @HeaderMap Map<String, String> headers, @QueryMap Map<String, String> map);

1、持有retrofit與原始的method物件。

2、獲取方法上的註解,獲取到的為:

 

3、獲取引數型別,獲取到的為:

 

 

 4、獲取引數上面的的註解,獲取到的為:

 

 

再看build()方法:

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

1、首先獲取請求介面卡。

2、建立請求結果的轉換器。

3、對方法上的註解進行解析。

4、構造ParameterHandler陣列。

5、對一些異常的判斷。

 

四、我們接下來對每一步進行講解。

1、首先獲取請求介面卡:

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

(1)、獲取方法的返回型別,返回型別不能是void

(2)、獲取方法上的註解。

(3)、呼叫retrofit.callAdapter(returnType, annotations)方法獲取請求的介面卡。(我們之前設定的請求介面卡都在retrofit物件中)

裡面關鍵的一步為:

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

skipPast為null,所以start為0;
遍歷我們之前設定給它的請求介面卡,根據返回型別與方法上的註解去找,找到了便返回。(我們這裡獲取到的callAdapter為RxJava2CallAdapter

 

2、建立請求結果的轉換器:

responseConverter = createResponseConverter()

這個與獲取請求的介面卡的過程是類似的,因此這裡就略過了。

 

3、解析方法上的註解:parseMethodAnnotation(annotation),我們用的是GET,所以下面會呼叫:

parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);

我們這裡value是空的,所以它只走了下面這些就返回了。

if (this.httpMethod != null) {
        throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod, httpMethod);
      }
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

 

4、構造ParameterHandler陣列

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

 

主要是這一個方法:

parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);

p為序號,parameterType為方法的引數型別,parameterAnnotations為引數的註解。

裡面就不細講了,這裡最終得到的是:

 

 對於一些異常的判斷就不多講了,比如:

不能有多個帶@Url註解的引數。

不能同時使用@Path與@Url註解。

被@QueryMap標註的引數型別必須是Map

@QueryMap註解的引數的key必須是String

至此,我們的ServiceMethod便構造完了。

 

 

五、我們回到代理的那個方法裡面,還差兩句沒有解析:

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

主要看serviceMethod.adapt(okHttpCall)

T adapt(Call<R> call) {
  return callAdapter.adapt(call);
}

這裡的callAdapter是RxJava2CallAdapter。

於是我們來到它的adapter方法:

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

首先我們看isAsync,這裡為false,為什麼呢?我們建立adapter的時候是這樣的:

RxJava2CallAdapterFactory.create()

public static RxJava2CallAdapterFactory create() {
  return new RxJava2CallAdapterFactory(null, false);
}

第二個引數便是isAsync

1、所以我們建立的responseObservable為CallExecuteObservable<>(call),(同步執行的類)

2、我們建立一個Observable<?> observable,這裡建立的是BodyObservable<>(responseObservable),將剛剛建立的responseObservable

傳進去。

3、最終將該observable傳出去。

service = retrofit.create(ApiService.class);
public interface ApiService {
    @GET
    Observable<ResponseBody> doGet(@Url String url, @HeaderMap Map<String, String> headers, @QueryMap Map<String, String> map);
}
service.doGet(url, header, params?.params)

也就是說,當我們呼叫service.doGet的時候,會走到代理的invoke方法,然後返回一個Observable

而該Observable只有在被訂閱的時候才會執行,而且我們用的是同步,所以還需要在外面自己切換到子執行緒執行。

當被訂閱的時候,該BodyObservable會呼叫subscribeActual:

 

BodyObservable(Observable<Response<T>> upstream) {
  this.upstream = upstream;
}
@Override protected void subscribeActual(Observer<? super T> observer) {
  upstream.subscribe(new BodyObserver<T>(observer));
}

 

而這個upstream便是剛剛傳進去的responseObservable,呼叫subscribe方法,最終會執行到responseObservable的subscribeActual方法。

@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
  // Since Call is a one-shot type, clone it for each new observer.
  Call<T> call = originalCall.clone();
  observer.onSubscribe(new CallDisposable(call));
  boolean terminated = false;
  try {
    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();call便是我們傳進來的自定義的OkHttpCall

在call.execute()裡面:

.
.
.
call = rawCall;
if (call == null) {
  try {
    call = rawCall = createRawCall();
  } catch (IOException | RuntimeException | Error e) {
    throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
    creationFailure = e;
    throw e;
  }
}
.
.
.
return parseResponse(call.execute());

createRawCall()獲取okhttp3.Call,call.execute()便是okhttp的網路請求了。

我們主要看怎麼獲取okhttp3.Call,以及對請求結果的解析parseResponse方法。

private okhttp3.Call createRawCall() throws IOException {
  okhttp3.Call call = serviceMethod.toCall(args);
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

ServiceMethod裡面:

/** Builds an HTTP request from method arguments. */
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
  RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
      contentType, hasBody, isFormEncoded, isMultipart);
  @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
  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 + ")");
  }
  for (int p = 0; p < argumentCount; p++) {
    handlers[p].apply(requestBuilder, args[p]);
  }
  return callFactory.newCall(requestBuilder.build());
}

方法主要是構造了request然後使用okhttp3.Call.Factory建立okhttp3.Call,而我們之前在構建ServiceMothod的構造的ParameterHandler<Object>[] handlers便參與了request的構建,主要是將之前解析到的引數,比如路徑,頭部資訊等新增到request裡面。

 

再看一下請求結果的解析parseResponse方法:

重點語句:

T body = serviceMethod.toResponse(catchingBody);

在看serviceMethod裡面的toResponse方法:

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

這裡便用到了我們之前設定的資料轉換器,對結果進行轉換。

 

以上便是大概的過程了。

 

 轉載請標明:https://www.cnblogs.com/tangZH/p/13723480.html

 

相關文章