Android網絡編程-Retrofit源碼角度分析Http

上一篇講解了OKHttp,本篇來介紹下它的黃金搭檔Retrofit,OKHttp+Retrofit是網絡框架的不二之選。同是Square出品,和OKHttp融合起來很是簡單。 Retofit是一個RESTful的HTTP網絡請求框架,有如下特色:html

  • 基於OKHttp
  • 經過註解配置網絡請求參數
  • 支持同步、異步請求
  • 支持多種序列化、反序列化格式
  • 解耦完全、模塊高度封裝,使用不少設計模式來實現

基本使用

下面講解的是官網的例子java

建立網絡請求接口

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
複製代碼

建立Retrofit實例(使用建造者模式)

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build();
複製代碼

建立網絡接口實例

GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("yeungeek");
複製代碼

發送網絡請求

默認返回的是OKHttpCall,實際真正發送請求的就是OKHttpandroid

同步

Response<List<Repo>> list = repos.execute()
複製代碼

異步

call.enqueue(new Callback<List<Repo>>() {
   @Override
   public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
   }

   @Override
   public void onFailure(Call<List<Repo>> call, Throwable t) {
   }
});
複製代碼

請求流程

具體的請求流程能夠分爲7大步驟 git

retrofit

  1. 解析網絡請求接口的註解,配置網絡請求參數
  2. 經過動態代理生成網絡請求對象
  3. 經過CallAdapter,將網絡請求對象進行平臺適配(Android,Java8)
  4. 經過網絡請求執行器(Call),發送網絡請求
  5. 經過Converter進行數據解析
  6. 經過回調執行器,進行線程切換
  7. 在主線程處理返回結果

Refrofit最大特色是使用了大量的設計模式,來進行解耦,下圖是完整的流程圖(來自Stay 在 Retrofit分析-漂亮的解耦套路): github

retrofit 流程圖
接下來經過源碼分析,詳細講解上面的流程

源碼分析

Retrofit初始化

Retrofit retrofit = new Retrofit  //1. Retrofit聲明
    .Builder()                    //2. Builder
    .baseUrl("https://api.github.com/")   //3. baseUrl
    .addConverterFactory(GsonConverterFactory.create())  //4. Converter Factory
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())  //5. CallAdapter Factory
    .build();                    //6. 生成實例
複製代碼

Retrofit聲明

在使用Retrofit時,首先經過建造者模式構建Retrofit。編程

public final class Retrofit {
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();

  final okhttp3.Call.Factory callFactory;
  final HttpUrl baseUrl;
  final List<Converter.Factory> converterFactories;
  final List<CallAdapter.Factory> callAdapterFactories;
  final @Nullable Executor callbackExecutor;
  final boolean validateEagerly;

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }
  ......
}
複製代碼
  • serviceMethodCache:網絡請求配置對象緩存,經過解析網絡請求接口後獲得請求對象
  • callFactory:網絡請求器工廠(Call),默認實現是OKHttp
  • baseUrl:網絡請求Url地址
  • converterFactories:數據轉換器工廠集合
  • callAdapterFactories:請求適配器工廠集合
  • callbackExecutor:回調方法執行器
  • validateEagerly:是否提早驗證請求方法

剩下的步驟都是來初始化上面的參數segmentfault

Builder

public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private 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;

    Builder(Platform platform) {
      this.platform = platform;
    }

    public Builder() {
      this(Platform.get());
    }
    ......
}
複製代碼

Builder中的參數和 Retrfit 是意義一一對應的,默認構造函數進行平臺的選擇設計模式

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();
  }
  ......
}
複製代碼

經過反射來判斷選擇Android仍是Java8,之前版本還有對IOS平臺的支持,最新版本已經去掉了。
咱們看下Android平臺:api

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();
      //默認的 CallAdapter
      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);
      }
    }
  }
複製代碼

baseUrl

public Builder baseUrl(String baseUrl) {
   checkNotNull(baseUrl, "baseUrl == null");
   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;
}
複製代碼

把String url 轉換成HttpUrl,會對baseUrl進行合法性校驗(URL參數是否是以"/"結尾)緩存

ConverterFactory

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

把factory加到數據轉換器集合中,看下GsonFactory.create()具體的實現:

public static GsonConverterFactory create(Gson gson) {
  if (gson == null) throw new NullPointerException("gson == null");
  return new GsonConverterFactory(gson);
}

private final Gson gson;

private GsonConverterFactory(Gson gson) {
  this.gson = gson;
}

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

@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
    Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
  TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
  return new GsonRequestBodyConverter<>(gson, adapter);
}
複製代碼

GsonConverterFactory使用Gson 爲初始化參數,實現responseBodyConverterrequestBodyConverter接口,進行真正的數據轉換處理。

CallAdapterFactory

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

把factory加到請求適配器工廠集合中,Android 平臺默認實現是ExecutorCallAdapterFactory,後面再進行詳細講解。

build

最後一步build生成Retrofit對象

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);
}
複製代碼
  • callFactory配置,默認OkHttpClient
  • callbackExecutor配置,Android 平臺默認使用MainThreadExecutor
  • callAdapterFactories配置,先加入自定義的callAdapter,而後再加入defaultCallAdapterFactory
  • converterFactories配置,先加入內建轉換器(BuiltInConverters),而後加入自定義的數據轉換器
  • 生成Retrofit對象

建立網絡接口實例

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
//建立接口實例
GitHubService service = retrofit.create(GitHubService.class);
//生成請求對象
Call<List<Repo>> repos = service.listRepos("yeungeek");
複製代碼

Retrofit經過外觀模式和動態代理生成網絡接口實例,網絡接口的請求參數從接口聲明獲取

create

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

create方法中最重要的是使用了動態代理,調用接口的方法都會到Proxy的invoke方法中,在invoke方法中最重要的就是下面三行代碼

ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
複製代碼

loadServiceMethod

該方法讀取網絡請求接口裏的方法,根據配置生成ServiceMethod對象

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

loadServiceMethod會先從cache中獲取對象,若是獲取不到,則經過建造者模式生成ServiceMethod對象。

new ServiceMethod.Builder<>(this, method).build();
複製代碼

ServiceMethod

final class ServiceMethod<R, T> {
  // Upper and lower characters, digits, underscores, and hyphens, starting with a character.
  static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
  static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
  static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

  private final okhttp3.Call.Factory callFactory;
  private final CallAdapter<R, T> callAdapter;

  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, R> responseConverter;
  private final String httpMethod;
  private final String relativeUrl;
  private final Headers headers;
  private final MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;

  ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }
  ......
}
複製代碼
  • callFactory:網絡請求器工廠,和retrofit對象聲明中的含義同樣
  • callAdapter:網絡請求適配器工廠
  • baseUrl:網絡請求Url地址
  • responseConverter:Response 數據轉換器
  • httpMethod:http 請求方法
  • relativeUrl:網絡請求相對地址
  • headers:網絡請求頭
  • contentType:網絡請求 body 類型
  • parameterHandlers:方法處理解析器

ServiceMethod.Builder

Builder(Retrofit retrofit, Method method) {
   this.retrofit = retrofit;
   this.method = method;
   this.methodAnnotations = method.getAnnotations();
   this.parameterTypes = method.getGenericParameterTypes();
   this.parameterAnnotationsArray = method.getParameterAnnotations();
}
複製代碼
  • methodAnnotations:網絡請求接口方法註解
  • parameterTypes:網絡請求接口方法裏的參數註解
  • parameterAnnotationsArray:網絡請求接口方法裏的註解內容

build

public ServiceMethod build() {
   //1. 從 Retrofit 中獲取網絡請求器
   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?");
   }
   //2. 從 Refrofit 中獲取數據轉換器
   responseConverter = createResponseConverter();
   for (Annotation annotation : methodAnnotations) {
   //3. 解析網絡請求接口中方法的註解
     parseMethodAnnotation(annotation);
   }
   .....
   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.");
     }

     //4. 建立ParameterHandler<?>,用來解析來解析參數使用到註解
     parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
   }
   ......
   return new ServiceMethod<>(this);
}
複製代碼

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

createResponseConverter:根據接口請求註解類型、返回類型,獲取數據數據轉換器

private Converter<ResponseBody, T> createResponseConverter() {
  //獲取接口請求的註解
  Annotation[] annotations = method.getAnnotations();
  try {
     //從Rtrofit中獲取數據轉換器
    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);
  }
}
複製代碼

parseMethodAnnotation:解析請求接口的方法註解,主要有如下標籤

  • Http請求方法
  • Headers
  • Multipart
  • FormUrlEncoded

parseParameter:對方法的參數註解進行解析
包含:Url,Path,Query,QueryName,QueryMap,Header,HeaderMap,Field,FieldMap,Part,PartMap,Body

private ParameterHandler<?> parseParameter(
    int p, Type parameterType, Annotation[] annotations) {
  ParameterHandler<?> result = null;
  for (Annotation annotation : annotations) {
    //參數註解解析
    ParameterHandler<?> annotationAction = parseParameterAnnotation(
        p, parameterType, annotations, annotation);
    if (annotationAction == null) {
      continue;
    }
    if (result != null) {
      throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
    }
    result = annotationAction;
  }
  if (result == null) {
    throw parameterError(p, "No Retrofit annotation found.");
  }
  return result;
}
複製代碼

OKHttpCall

根據serviceMethod和請求參數,建立OkHttpCall對象

final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;
  private final @Nullable Object[] args;

  private volatile boolean canceled;

  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;
  @GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException.
  private @Nullable Throwable creationFailure;
  @GuardedBy("this")
  private boolean executed;

  OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }
  ......
}
複製代碼

serviceMethod和 args不作介紹了

  • rawCall:OKHttp,真正發送網絡請求
  • canceled:取消請求標誌位
  • executed:是否執行標誌位
  • creationFailure:異常標誌位

adapt

根據ServiceMethod的中的callAdapter,來真正執行adapt方法
ServiceMethod的adapt方法

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

Android 默認的返回 ExecutorCallAdapterFactory的Call
這裏使用了靜態代理delegate,加入一些額外的操做

public Call<Object> adapt(Call<Object> call) {
   return new ExecutorCallAdapterFactory.ExecutorCallbackCall(ExecutorCallAdapterFactory.this.callbackExecutor, call);
}
......
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
   this.callbackExecutor = callbackExecutor;
   this.delegate = delegate;
}
複製代碼

RxJavaCallAdapterFactory返回的是Observable

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

通過上面幾步操做 Call<List<Repo>> repos = service.listRepos("yeungeek"),返回了一個 OKHttpCall 對象。

發送網絡請求

請求和 OKHttp 同樣,分爲同步請求和異步請求

同步請求

execute 首先會調用ExecutorCallbackCall的execute方法:

@Override public Response<T> execute() throws IOException {
  return delegate.execute();
}
複製代碼

delegate代理實際是 OKHttpCall,最終會調用OKHttpCall的execute方法

@Override public Response<T> execute() throws IOException {
  okhttp3.Call call;
  ......
    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;
      }
    }
  }
  if (canceled) {
    call.cancel();
  }
  return parseResponse(call.execute());
}
複製代碼

createRawCall

建立真正發送的請求Request對象

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的 toCall 方法
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
  //Request 的 builder 生成 Reuqest 對象
  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());
}
複製代碼

parseResponse

調用OKHttp的execute發送網絡請求,根據網絡請求結果再進行結果解析

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

先對響應碼進行處理,再經過serviceMethod.toResponse選擇數據轉換器,對數據進行解析後,生成Response對象返回

異步請求

異步請求的流程和同步請求同樣,就是再回調處理會進行線程切換
ExecutorCallbackCall的enqueue方法

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

代理執行加入了線程切換到邏輯,經過callbackExecutor切換到主線程
OKHttpCall的enqueue方法:

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

    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 {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }
複製代碼

若是使用到RxJava,在上一節已經提到, adapt會進行適配,RxJava2CallAdapter的adapt方法中有對RxJava轉換,具體邏輯實現這邊先不展開

Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);
複製代碼

Retrofit中的HTTP實現

Retrofit真正請求網絡,底層使用的是OKHttp,Refrofit主要負責網絡請求接口的封裝,看下源碼中與HTTP相關的註解

Retrofit-HTTP
這些註解都是在接口上的聲明,主要是HTTP的請求方法和參數,具體能夠參考 Android網絡編程-HTTP/HTTPS,這裏也不具體展開了

設計模式應用

咱們再回顧下這張流程圖:

retrofit-stay

構建者模式

這個模式運用的比較多,Retrofit的Builder,ServiceMethod的Builder等
設計模式能夠參考建造者模式(Bulider模式)詳解

工廠模式

在Retrofit 初始化,addCallAdapterFactory中的CallAdapter就是用工廠方法模式

public interface CallAdapter<R, T> {
  Type responseType();
  T adapt(Call<R> call);

  abstract class Factory {
    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);

    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}
複製代碼

實現Factory中抽象方法get,就會返回不一樣的 CallAdapter 對象 設計模式能夠參考工廠方法模式(詳解版)

外觀模式(門面模式)

Retrofit 就是一個典型的外觀類,它屏蔽了全部的實現細節,提供給使用者方便的接口,統一調用建立接口實例和網絡請求配置的方法
設計模式能夠參考外觀模式(Facade模式)詳解

策略模式

主要應用CallAdapter類的adapt方法,在 Retrofit addCallAdapterFactory,對應 Factory 生成不一樣的CallAdapter,adapt就能夠調用到不一樣實現
CallAdapter就是一個Strategy,Retrofit 對應上下文(Context) 設計模式能夠參考策略模式(策略設計模式)詳解

適配器模式

仍是在CallAdapter獲得應用,Retrofit能夠適配Android,Java8,RxJava,guava等平臺, 不一樣平臺有不一樣的特性,addCallAdapterFactory能夠生成不一樣的平臺的CallAdapter,把不一樣平臺的特性,統一在一個接口中 設計模式能夠參考適配器模式(Adapter模式)詳解

代理模式

Retrofit實例的create方法,使用了動態代理模式,網絡請求接口,都會調用到Proxy.newProxyInstance的 invoke 方法中

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

除了使用動態代理,Retrofit 還使用了靜態代理模式,ExecutorCallbackCall的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);
        }
      });
    }
  });
}
複製代碼

設計模式能夠參考代理模式(代理設計模式)詳解
Retrofit使用了大量的設計模式,上面只是在主流過程使用到的,其餘設計模式的應用,你們能夠繼續深刻源碼去分析,總之,Refrofit框架是很是值得深刻研究的框架

參考

相關文章
相關標籤/搜索