Source code analysis of Android mainstream tripartite libraries: Retrofit

1. Basic use process

1. Define HTTP API to describe the request

public interface GitHubService {

     @GET("users/{user}/repos")
     Call<List<Repo>> listRepos(@Path("user") String user);
}
复制代码

2. Create Retrofit and generate API implementation (note: the annotation above the method represents the interface part of the request, the return type is the return value type of the request, and the parameters of the method are the requested parameters)

// 1.Retrofit构建过程
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();

// 2.创建网络请求接口类实例过程
GitHubService service = retrofit.create(GitHubService.class);
复制代码

3. Call the API method, generate Call, and execute the request

// 3.生成并执行请求过程
Call<List<Repo>> repos = service.listRepos("octocat");
repos.execute() or repos.enqueue()
复制代码

The basic use process of Retrofit is very concise, but conciseness does not mean simplicity. In order to achieve this concise use process, Retrofit uses excellent architecture design and a large number of design patterns internally. After I have analyzed the source code of the latest version of Retrofit and a lot of excellent After analyzing the Retrofit source code article, I found that if you want to truly understand the core source code process and design ideas inside Retrofit, you need to have a certain understanding of these nine design patterns, as follows:

1.Retrofit构建过程 
建造者模式、工厂方法模式

2.创建网络请求接口实例过程
外观模式、代理模式、单例模式、策略模式、装饰模式(建造者模式)

3.生成并执行请求过程
适配器模式(代理模式、装饰模式)
复制代码

Secondly, the need to have some understanding of OKHttp source, do not know if you can read this Android mainstream-party library source code analysis (a deep understanding OKHttp source) . Finally, let us follow the above process to go deep into the Retrofit source code and comprehend the beauty of the design it brings us .

Two, Retrofit construction process

1. Analysis of Retrofit core objects

First of all, there is a global variable in Retrofit that is very important. In versions before V2.5, LinkedHashMap() is used. It is a network request configuration object, which is obtained after analyzing the method annotations in the network request interface.

public final class Retrofit {

    // 网络请求配置对象,存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等
    private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
复制代码

Retrofit uses the builder mode to create a Retrofit instance through the internal Builder class, as follows:

public static final class Builder {

    // 平台类型对象(Platform -> Android)
    private final Platform platform;
    // 网络请求工厂,默认使用OkHttpCall(工厂方法模式)
    private @Nullable okhttp3.Call.Factory callFactory;
    // 网络请求的url地址
    private @Nullable HttpUrl baseUrl;
    // 数据转换器工厂的集合
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    // 网络请求适配器工厂的集合,默认是ExecutorCallAdapterFactory
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    // 回调方法执行器,在 Android 上默认是封装了 handler 的 MainThreadExecutor, 默认作用是:切换线程(子线程 -> 主线程)
    private @Nullable Executor callbackExecutor;
    // 一个开关,为true则会缓存创建的ServiceMethod
    private boolean validateEagerly;
复制代码

2. Builder internal structure

Let's take a look at what the internal structure of Builder does.

public static final class Builder {

    ...

    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 {
        // 使用JVM加载类的方式判断是否是Android平台
        Class.forName("android.os.Build");
        if (Build.VERSION.SDK_INT != 0) {
          return new Android();
        }
      } catch (ClassNotFoundException ignored) {
      }
      try {
        // 同时支持Java平台
        Class.forName("java.util.Optional");
        return new Java8();
      } catch (ClassNotFoundException ignored) {
      }
      return new Platform();
    }

static class Android extends Platform {

    ...

    @Override public Executor defaultCallbackExecutor() {
        //切换线程(子线程 -> 主线程)
        return new MainThreadExecutor();
    }

    // 创建默认的网络请求适配器工厂,如果是Android7.0或Java8上,则使
    // 用了并发包中的CompletableFuture保证了回调的同步
    // 在Retrofit中提供了四种CallAdapterFactory(策略模式):
    // ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、
    // va8CallAdapterFactory、RxJavaCallAdapterFactory
    @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 List<? extends Converter.Factory> defaultConverterFactories() {
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }

    ...

    static class MainThreadExecutor implements Executor {

        // 获取Android 主线程的Handler 
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override public void execute(Runnable r) {

            // 在UI线程对网络请求返回数据处理
            handler.post(r);
        }
    }
}

复制代码

As you can see, the default Platform, callAdapterFactories and callbackExecutor are set during the internal construction of the Builder.

3. Add baseUrl

It's very simple. The process of converting String type url to OkHttp HttpUrl is as follows:

/**
 * Set the API base URL.
 *
 * @see #baseUrl(HttpUrl)
 */
public Builder baseUrl(String baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    return baseUrl(HttpUrl.get(baseUrl));
}

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

复制代码

4. Add GsonConverterFactory

First, see the source code of GsonConverterFactory.creat().

public final class GsonConverterFactory extends Converter.Factory {

    public static GsonConverterFactory create() {
        return create(new Gson());
    }

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

    private final Gson gson;

    // 创建了一个含有Gson对象实例的GsonConverterFactory
    private GsonConverterFactory(Gson gson) {
        this.gson = gson;
    }
复制代码

Then, look inside the addConverterFactory() method.

public Builder addConverterFactory(Converter.Factory factory) {
    converterFactories.add(checkNotNull(factory, "factory null"));
    return this;
}
复制代码

It can be seen that this step is to put a GsonConverterFactory containing an instance of the Gson object into the data converter factory converterFactories.

5. Build process

public Retrofit build() {

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

    okhttp3.Call.Factory callFactory = this.callFactory;
    if (callFactory == null) {
        // 默认使用okhttp
         callFactory = new OkHttpClient();
    }

    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {
        // Android默认的callbackExecutor
        callbackExecutor = platform.defaultCallbackExecutor();
    }

    // Make a defensive copy of the adapters and add the defaultCall adapter.
    List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    // 添加默认适配器工厂在集合尾部
    callAdapterFactories.addAll(platform.defaultCallAdapterFactorisca  llbackExecutor));

    // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories = new ArrayList<>(
        1 + 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 thatconsumeall types.
    converterFactories.add(new BuiltInConverters());
    converterFactories.addAll(this.converterFactories);
    converterFactories.addAll(platform.defaultConverterFactories();

    return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
        unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);

}
复制代码

As you can see, the 6 core objects we saw in the Builder class have been configured into the Retrofit object.

Three, create a network request interface instance process

retrofit.create() uses the appearance mode and the proxy mode to create the interface instance of the network request, we analyze the create method.

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
        // 判断是否需要提前缓存ServiceMethod对象
        eagerlyValidateMethods(service);
    }

    // 使用动态代理拿到请求接口所有注解配置后,创建网络请求接口实例
    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);
            }
            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)) {
      loadServiceMethod(method);
    }
  }
}
复制代码

Continue to look at the internal process of 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);
            // 可以看到,最终加入到ConcurrentHashMap缓存中
            serviceMethodCache.put(method, result);
      }
    }
    return result;
}

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method   method) {
        // 通过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.");
        }

        // 最终是通过HttpServiceMethod构建的请求方法
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
    }

    abstract T invoke(Object[] args);
}
复制代码

The following is the core process of request construction

According to the source code of RequestFactory#Builder construction method and parseAnnotations method, it can be known that its function is to parse annotation configuration.

Builder(Retrofit retrofit, Method method) {
    this.retrofit = retrofit;
    this.method = method;
    // 获取网络请求接口方法里的注释
    this.methodAnnotations = method.getAnnotations();
    // 获取网络请求接口方法里的参数类型       
    this.parameterTypes = method.getGenericParameterTypes();
    // 获取网络请求接口方法里的注解内容    
    this.parameterAnnotationsArray = method.getParameterAnnotations();
}
复制代码

Then look at the internal process of HttpServiceMethod.parseAnnotations().

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {

    //1.根据网络请求接口方法的返回值和注解类型,
    // 从Retrofit对象中获取对应的网络请求适配器
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit,method);

    // 得到响应类型
    Type responseType = callAdapter.responseType();

    ...

    //2.根据网络请求接口方法的返回值和注解类型从Retrofit对象中获取对应的数据转换器 
    Converter<ResponseBody, ResponseT>responseConverter =
        createResponseConverter(retrofit,method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;

    return newHttpServiceMethod<>(requestFactory, callFactory, callAdapter,responseConverter);
}
复制代码
1.createCallAdapter(retrofit, method)
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT>     createCallAdapter(
      Retrofit retrofit, Method method) {

    // 获取网络请求接口里方法的返回值类型
    Type returnType = method.getGenericReturnType();

    // 获取网络请求接口接口里的注解
    Annotation[] annotations = method.getAnnotations();
    try {
      //noinspection unchecked
      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);
    }
}

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
  Annotation[] annotations) {
    ...

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    // 遍历 CallAdapter.Factory 集合寻找合适的工厂
    for (int i = start, count = callAdapterFactories.size(); i <count; i++) {
        CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        if (adapter != null) {
          return adapter;
        }
    }
}

复制代码
2.createResponseConverter(Retrofit retrofit, Method method, Type responseType)
 private static <ResponseT> Converter<ResponseBody, ResponseT>  createResponseConverter(
     Retrofit retrofit, Method method, Type responseType) {
   Annotation[] annotations = method.getAnnotations();
   try {
     return retrofit.responseBodyConverter(responseType,annotations);
   } catch (RuntimeException e) { // Wide exception range because    factories are user code.
     throw methodError(method, e, "Unable to create converter for%s",   responseType);
   }
}

public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
}

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
  @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
...

int start = converterFactories.indexOf(skipPast) + 1;
// 遍历 Converter.Factory 集合并寻找合适的工厂, 这里是GsonResponseBodyConverter
for (int i = start, count = converterFactories.size(); i < count; i++) {
  Converter<ResponseBody, ?> converter =
      converterFactories.get(i).responseBodyConverter(type, annotations, this);
  if (converter != null) {
    //noinspection unchecked
    return (Converter<ResponseBody, T>) converter;
  }
}
复制代码

Finally, execute the invoke method of HttpServiceMethod

@Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
复制代码

Finally, an ExecutorCallbackCall object is created in adapt. It is a decorator, and OkHttpCall is what actually executes network requests inside it.

Fourth, create an instance of the network request interface class and execute the request process

1、service.listRepos()

1、Call<List<Repo>> repos = service.listRepos("octocat");
复制代码

The service object is a dynamic proxy object Proxy.newProxyInstance(), which will be intercepted when calling getCall(), and then call its own InvocationHandler#invoke() to get the final Call object.

2. Synchronous execution process repos.execute()

@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else if (creationFailure instanceof RuntimeException) {
          throw (RuntimeException) creationFailure;
        } else {
          throw (Error) creationFailure;
        }
      }

      call = rawCall;
      if (call == null) {
        try {
          // 创建一个OkHttp的Request对象请求
          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();
    }

    // 调用OkHttpCall的execute()发送网络请求(同步),
    // 并解析网络请求返回的数据
    return parseResponse(call.execute());
}

private okhttp3.Call createRawCall() throws IOException {
    // 创建 一个okhttp3.Request
    okhttp3.Call call =
    callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
}

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

    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;
    }
}
复制代码

3. Asynchronous request process response.enqueque

@Override 
public void enqueue(final Callback<T> callback) {

    // 使用静态代理 delegate进行异步请求 
    delegate.enqueue(new Callback<T>() {

      @Override 
      public void onResponse(Call<T> call, finalResponse<T>response) {
        // 线程切换,在主线程显示结果
        callbackExecutor.execute(new Runnable() {
            @Override 
             public void run() {
            if (delegate.isCanceled()) {
              callback.onFailure(ExecutorCallbackCall.this, newIOException("Canceled"));
            } else {
              callback.onResponse(ExecutorCallbackCall.this,respons);
            }
          }
        });
      }
      @Override 
      public void onFailure(Call<T> call, final Throwable t) {
        callbackExecutor.execute(new Runnable() {
          @Override public void run() {
            callback.onFailure(ExecutorCallbackCall.this, t);
          }
        });
      }
    });
}
复制代码

Take a look at the internal process of delegate.enqueue.

@Override 
public void enqueue(final Callback<T> callback) {

    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 {
          // 创建OkHttp的Request对象,再封装成OkHttp.call
          // 方法同发送同步请求,此处上面已分析
          call = rawCall = createRawCall(); 
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }

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

  okhttp3.Call call;
  Throwable failure;

  ...

  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) {
        throwIfFatal(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();
      }
    }
  });
}
复制代码

If you see this, congratulations, you already have a more in-depth understanding of Retrofit, but the author still recommends that you take the initiative to cooperate with the latest version of Retrofit to understand it step by step. Only this way, You can see its true heart, and finally attach a flow chart of Stay’s Retrofit source code. It should be noted that this is the process of the previous version of V2.5. However, after reading the source code analysis above, we know that, The main process is unchanged.

Five, summary

In essence, Retrofit is just a package library of RESTful HTTP network request framework. However, it encapsulates OkHttp through a large number of design patterns inside, making users feel that it is very simple and easy to understand. It mainly uses a dynamic proxy method to dynamically parse the annotations of the network request interface into an HTTP request, and finally execute the request process. Well, at this point, the network library analysis part of our Android mainstream tripartite library source code analysis has been completed. Next, I will bring you the source code analysis of the most popular image loading framework Glide, so stay tuned~

Six, study notes sharing

In order to facilitate everyone to learn more about Android-related source code, the third framework has been added. I have compiled a copy of "Android Related Source Code Analysis" and "Design Ideas Interpretation of Open Source Framework", partners in need can like + follow, and send me a private message!
Android related source code interpretation directory
Android related source code interpretation part of the analytical content
Open source framework to interpret the catalog and part of the analysis content

Partners who need the above study notes can like + follow, and send me a private message!

Guess you like

Origin blog.csdn.net/star_nwe/article/details/111681908