美文网首页
Retrofit流程+源码分析

Retrofit流程+源码分析

作者: 一碗清汤面_ | 来源:发表于2020-04-27 10:38 被阅读0次

    前言

    前一篇分析了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());
        }
    

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

    三、同/异步请求数据

    同步请求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;
        }
      }
    

    异步请求call.enqueue(Callback<T> 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流程+源码分析

          本文链接:https://www.haomeiwen.com/subject/khewihtx.html