Android Retrofit原理深入探索

手机APP/开发
295
0
0
2023-06-11
标签   Android
目录
  • 序章
  • Retrofit构建过程
  • 创建网络请求接口实例过程
  • 执行请求过程
  • 总结

序章

首先引入依赖

  implementation 'com.squareup.retrofit2:retrofit:2.9.0'

在原理之前,我们先来回忆一下Retrofit的基本使用

1、定义接口

interface MyService {
    @GET("gallery/{imageType}/response")
    fun getImages(@Path("imageType") imageType: String): Call<List<String>>
}

2、构建Retrofit,创建网络请求接口类实例

val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .build()
val myService = retrofit.create(MyService::class.java)

3、生成Call,执行请求

val resp = myService.getImages("banner")
resp.enqueue(object : Callback<List<String>> {
    override fun onResponse(call: Call<List<String>>, response: Response<List<String>>) {
        TODO("Not yet implemented")
    }
    override fun onFailure(call: Call<List<String>>, t: Throwable) {
        TODO("Not yet implemented")
    }
})

这样一个基本的网络请求就搞定了,使用很简洁,正是因为其内部使用了大量的设计模式和优秀的架构设计,才得以使其如此方便地进行网络请求,下面我们就一起来探索探索Retrofit的设计之美。

Retrofit构建过程

使用了建造者模式通过内部静态类Builder构建一个Retrofit实例,这里只列出了部分方法,其他类似

public static final class Builder {
    private final Platform platform;
    // 网络请求工厂,工厂方法模式
    private @Nullable okhttp.Call.Factory callFactory;
    // 网络请求地址
    private @Nullable HttpUrl baseUrl;
    // 数据转换器工厂的集合
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    // 网络请求适配器工厂的集合,默认是ExecutorCallAdapterFactory
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    // 回调方法执行器,用于切换线程
    private @Nullable Executor callbackExecutor;
    // 一个开关,为true则会缓存创建的ServiceMethod
    private boolean validateEagerly;
    //......
    public Builder baseUrl(String baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null");
      return baseUrl(HttpUrl.get(baseUrl));
    }
    public Builder baseUrl(HttpUrl baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();if (!"".equals(pathSegments.get(pathSegments.size() -))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }this.baseUrl = baseUrl;
      return this;
    }
    // 将一个含有Gson对象实例的GsonConverterFactory放入数据转换器工厂
    public Builder addConverterFactory(Converter.Factory factory) {converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }
    //......
}

通过build,我们上面Builder类中的参数对象都配置到了Retrofit对象中。

public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }
  okhttp.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.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories =
      new ArrayList<>( + this.converterFactories.size() + platform.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());
  return new Retrofit(
      callFactory,
      baseUrl,
      unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories),
      callbackExecutor,
      validateEagerly);
}

创建网络请求接口实例过程

使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例。

  public <T> T create(final Class<T> service) {  validateServiceInterface(service);
return (T)
    Proxy.newProxyInstance(
        service.getClassLoader(),
        new Class<?>[] {service},
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[];
          @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);
            }
            args = args != null ? args : emptyArgs;
            return platform.isDefaultMethod(method)
                ? platform.invokeDefaultMethod(method, service, proxy, args)
                : loadServiceMethod(method).invoke(args);
          }
        });
  }

跟踪 loadServiceMethod,parseAnnotations解析注解配置得到ServiceMethod,然后加入到serviceMethodCache缓存中,是一个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;
  }
abstract class ServiceMethod<T> {static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
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.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }abstract @Nullable T invoke(Object[] args);
}

执行请求过程

  public void enqueue(final Callback<T> callback) {  Objects.requireNonNull(callback, "callback == null");
okhttp.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 {
      // 创建一个OkHttp的Request对象请求
      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 okhttp.Callback() {
      @Override
      public void onResponse(okhttp.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          // 解析网络请求返回的数据
          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(okhttp.Call call, IOException e) {
        callFailure(e);
      }
      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }
    });
  }
  Response<T> parseResponse(okhttp.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 < || 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 == || code == 205) {
  rawBody.close();
  return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
  // 将响应体转为Java对象
  T body = responseConverter.convert(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;
}
  }

总结

首先,使用建造者模式通过Builder构建一个Retrofit实例,Builder类中的参数对象都配置到Retrofit对象中,然后使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例,生成OkHttp请求,通过callAdapterFactory找到对应的执行器,比如RxJava2CallAdapterFactory,最后通过ConverterFactory将返回数据解析成JavaBean,使用者只需关心请求参数,内部实现由Retrofit封装完成,底层请求还是基于okhttp实现的。