阅读 728

Android-开源框架分析-【Retrofit】

前言

前一篇分析了OkHttp的源码和流程,这一篇依然从Retrofit的使用角度并结合源码来分析,当然Retrofit是基于OkHttp的,所以OkHttp源码-流程-拦截器分析还是有必要了解的,而且Retrofit中使用了很多的设计模式,需要提前预览。

  • 在开始流程前需要先看一下整体的流程图以及设计模式,这里就用了之前的Stay的Retrofit源码流程图,虽然更新了很多版本,但主要部分还是没变化的,看完这图,结合代码,最后再看图,再自己看源码总结,会更好理解的。

Retrofit流程图

流程及分析

1.定义一个请求接口,包含请求方法

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

2.使用retrofit请求

   val retrofit = Retrofit.Builder()
          .baseUrl("https://api.github.com/")
          .addConverterFactory(GsonConverterFactory.create())
          .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
          .build()

   val api = retrofit.create(Api::class.java)
   val call = api.listRepos("")

   call.execute()

   call.enqueue(object :retrofit2.Callback<List<Repo>> {
      override fun onFailure(call: retrofit2.Call<List<Repo>>, t: Throwable) {}

      override fun onResponse(call: retrofit2.Call<List<Repo>>, response: retrofit2.Response<List<Repo>>) {}
   })
复制代码

一、构建Retrofit实例

先来看看Retrofit中的成员变量

//解析接口注解后相关信息的存储
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
//请求工厂、默认为OkHttpClient
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
//数据转换器工厂的集合,例如Gson转换
final List<Converter.Factory> converterFactories;
//网络请求适配器的集合
final List<CallAdapter.Factory> callAdapterFactories;
//回调执行器,在Android平台上就是通过Handler切换线程
final @Nullable Executor callbackExecutor;
//用来判断是否立即对我们的请求方法进行解析
final boolean validateEagerly;
复制代码

1.Builder()方法

    Builder(Platform platform) {
      this.platform = platform;
    }
    
    public Builder() {
      this(Platform.get());
    }
复制代码

Platform.get() 获取当前平台,一般是Android,当然也支持其他平台比如Java8等

class Platform {
  private static final Platform PLATFORM = findPlatform();
//通过findPlatfrom()获取平台信息
  static Platform get() {
    return PLATFORM;          
  }
  //比较SDK版本 不空就返回Android平台
  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();                          
      }
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform(true);
  }
  ...
  static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    //通过Handler切换到主线程
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}
复制代码

2.baseUrl() 将String类型的URL转换为请求用的URL

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() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
}
复制代码

3.addConverterFactory(GsonConverterFactory.create()) 添加转换器

//主要就是创建带Gson对象的转换工厂
GsonConverterFactory.create()  
//将带有Gson的转换器工厂添加到集合中
public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
}
复制代码

4.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

添加一个请求的适配器工厂最后添加到Builde中的变量中,通过设计模式,像现在支持Kotlin的协程,也只需要切换工厂即可

5.build() 完成创建Retrofit实例

 public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //一般不设置的话 就是默认OkHttpClient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //这里其实就是MainThreadExecutor()
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

  ....
      //创建了Retrfit 为前面的变量赋值
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
复制代码

二、创建接口实例

val api = retrofit.create(Api::class.java) 
复制代码

这部分用了动态代理以及外观模式创建了接口实例,以下是源码

  public <T> T create(final Class<T> service) {
    //1.主要做了一些验证比如是否接口以及是否需要提前缓存ServiceMethod对象
    validateServiceInterface(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);
          }
        });
  }
复制代码

ServiceMethod<?> loadServiceMethod(Method method) 在这个方法中解析接口中的注解等信息以及信息的缓存

  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);
        //将解析出的信息添加到ConcurrentHashMap中供之后用
        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);
   // ...中间做了些验证 省略了
   //将接口方法的调用调整为HTTP请求
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

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

具体的解析 RequestFactory parseAnnotations(Retrofit retrofit, Method method)

    static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
        return new Builder(retrofit, 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();
    }

    RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
        //循环解析注解
        parseMethodAnnotation(annotation);
      }
      ...
      return new RequestFactory(this);
    }
复制代码

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

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
   ...
    //1.从Retrofit.java中的callAdapterFactories集合中获取对应的请求适配器
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    ...
    //2.从Retrofit.java中的converterFactories集合中获取对应的数据转换器
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    //检查是否kotlin协程中挂起的函数
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } 
    ...
  }
复制代码

最终转接到OkHttp的Call

 // loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

 @Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
复制代码

三、同/异步请求数据

1.同步请求call.execute()

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

    synchronized (this) {
      ...
      call = rawCall;
      if (call == null) {
        try {
          //1.这里创建了OkHttp的call
          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();
    }
    //2.解析OkHttp请求回来的数据
    return parseResponse(call.execute());
  }

  //callFactory就是OkHttpClient 
  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;
  }

  //将OkHttp请求回的Response做解析
  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    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 {
      //通过之前的赋值的转换器 将数据转为具体类型
      T body = responseConverter.convert(catchingBody);  
      //封装到Response中返回
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      catchingBody.throwIfCaught();
      throw e;
    }
  }
复制代码

2.异步请求call.enqueue(Callback callback)

  @Override public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(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 {
          //依旧是使用了OkHttp的Call
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

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

    if (canceled) {
      call.cancel();
    }
    //依旧是使用了OkHttp的同步请求
    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) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }

      @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) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }
    });
  }
复制代码

看到这里基本上的整体流程也就差不多了 再结合开头的图会比较清晰一点,如果自己能看一遍源码,那你的理解会更深一个层次。

总结

总的来说,Retrofit是基于OkHttp的二次封装,通过动态代理将数据请求转接于OkHttp请求并通过使用设计模式做到了低耦合,高扩展性,使用方便的网络请求框架,它其中很多的点值得我们去揣摩,学习,并且运用到我们自己的项目中。

最后

  • 如果文中如果有什么纰漏欢迎讨论与指出。
  • 参考

Retrofit分析-漂亮的解耦套路 Android主流三方库源码分析(二、深入理解Retrofit源码)

文章分类
Android
文章标签