阅读 123

常用轮子之Retrofit基本使用及原理

不忘初心 砥砺前行, Tomorrow Is Another Day !

相关文章

本文概要:

  1. 引言
    • okHttp、urlConnection、httpClient、volley、retrofit之间的关系
  2. Retrofit的使用-简单介绍
  3. Retrofit的原理-重点分析

一. 引言

在分析Retrofit之前,我们需要对基本的网络以及网络框架有个综合的对比认识.

okHttp、urlConnection、httpClient、volley、retrofit之间的关系

  • okHttp、urlConnection、httpClient 这三者是底层的网络库.
  • volley与retrofit属于更高层的网络库
  • volley对urlConnection和httpClient的进行了封装,由于volley良好的扩展性,它还能配置使用okHttp作为底层库
  • retrofit则是在okhttp的基础上封装了线程的切换及网络数据解析

二. Retrofit的使用

Retrofit的使用比较简单,基本是就是通过三类注解方法注解,参数注解. 这里就不再讲述了,找了一篇个人感觉比较全面的文章你真的会用Retrofit2吗?Retrofit2完全教程进行参考学习.我们重点进行原理分析.

三. 基本原理

3.1 Retrofit的创建

源码版本2.5.0
Retrofit是通过动态代理的方式创建各种网络接口的代理.

关于动态代理,笔者另起了篇讲述.设计模式之代理模式如有兴趣的可以看一下.最后我们回归正题.

使用过程一般都是通过建造者的build方法来构建Retorfit对象.我们就从Retorfit对象的创建开始,

使用示例-1

mRetrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .callFactory(okHttpClient)
                .build();
复制代码

直接看build方法的对应源码

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

      // 1.初始化callFactory,如果未设置则默认设置一个OkHttpClient

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      // 2.初始化回调执行器,用于回调到UI线程
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // 3.初始化适配器工厂集合,添加一个默认适配器工厂(ExecutorCallAdapterFactory)
      //用于适配返回类型,如默认支持的Call<T>
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // 4.初始化转换器集合
      //用于网络响应的解析
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      //...省略部分代码

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  
复制代码

在build方法里,初始化时会通过platform对象添加一些默认的适配器,转换器,以及回调执行器.我们看具体的添加操作.

对应源码

  static class Android extends Platform {
    @IgnoreJRERequirement // Guarded by API check.
    @Override boolean isDefaultMethod(Method method) {
      if (Build.VERSION.SDK_INT < 24) {
        return false;
      }
      return method.isDefault();
    }
    //添加默认回调执行器
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    //添加默认的适配器工厂(ExecutorCallAdapterFactory)
    @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 int defaultCallAdapterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
    }

    //添加默认的转换器工厂
    @Override List<? extends Converter.Factory> defaultConverterFactories() {
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }

    @Override int defaultConverterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
    }

    static class MainThreadExecutor implements Executor {
      //绑定主线程的looper
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        //回调到主线程执行
        handler.post(r);
      }
    }
  }
复制代码

至此Retorfit对象创建过程就分析完了,做一个小结.

对于Retorfit的创建,进行一系列的初始化操作.

  • 初始化callFactory
  • 初始化"三器"
    • 回调执行器,用于回调到UI线程
    • 适配器工厂,用于适配返回的类型
    • 转换器工厂,用于解析网络响应

3.2 Call的创建

Call的创建过程实质是网络接口的实现过程

Rerofit对象创建完成后,调用create方法时来实现我们定义的网络接口ApiService,采用的就是动态代理.

使用示例-2

定义的网络接口类
public interface ApiService{
    @GET
    Observable<IDocViewBean> oaFileUpload(@Url String url,
                                          @Query("token") String token,
                                          @Query("mode") String mode,
                                          @Query("url") String urlFile);
}

ApiService apiService = retrofit.create(ApiService.class);
复制代码

对应源码

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    /*
     * 返回了网络接口的代理对象
     */
    //当我们调用代理对象的接口方法时,会触发InvocationHandler的invoke方法.
    //如调用apiService.oaFileUpload(...)时,会完成oaFileUpload的实现,并返回一个Call<T>
    //如调用apiService.oaFileUpload(...)时,会完成oaFileUpload的实现,并返回一个Call<T>
    //如调用apiService.oaFileUpload(...)时,会完成oaFileUpload的实现,并返回一个Call<T>
    //重要话说三遍,这一句理解了后面就容易了.
    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);
            }
            //加载网络接口的方法,如加载oaFileUpload方法并调用.
             /**
             * 第一大步:先分析loadServiceMethod(method)获取到网络接口方法对象(ServiceMethod对象)
             * 第二大步:调用ServiceMethod的invoke.
             */
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

    
复制代码

3.2.1 第一大步

接着我们看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);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
复制代码

对网络接口的方法进行解析调用的了ServiceMethod.parseAnnotations,实际调用的是它的子类HttpServiceMethod.parseAnnotations方法.这里我们直接看子类的方法.

对应源码

//HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    //创建CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();
    if (responseType == Response.class || responseType == okhttp3.Response.class) {
      throw methodError(method, "'"
          + Utils.getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }
    //创建转换器
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
  }
  
  
  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();
    Annotation[] annotations = method.getAnnotations();
    try {
      //noinspection unchecked
      //里面通过retrofit对象的callAdapter方法获取CallAdapter对象
      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);
    }
  }
复制代码

createCallAdapter方法调用了retrofit对象的callAdapter方法获取CallAdapter对象.接着看retrofit的CallAdapter方法.

对应源码

//retrofit.java
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    //再接着往下看
    return nextCallAdapter(null, returnType, annotations);
  }
  
  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    //先遍历callAdapterFactories集合
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      //再通过网络接口的返回类型(returnType)来获取适配器工厂(CallAdapter.Factory),最终获取到CallAdapter对象.
      //再通过网络接口的返回类型(returnType)来获取适配器工厂(CallAdapter.Factory),最终获取到CallAdapter对象.
      //再通过网络接口的返回类型(returnType)来获取适配器工厂(CallAdapter.Factory),最终获取到CallAdapter对象.
      //重要的话说三遍.
      //由于之前在Retrofit对象创建阶段时,有默认设置CallAdapter.Factory为ExecutorCallAdapterFactory,那么遍历时就会获取到它.
      //最后一起看下ExecutorCallAdapterFactory的get方法.
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    
复制代码
//ExecutorCallAdapterFactory.java
@Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //检测返回类型是不是CALL
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    //返回一个CallAdapter对象,终于找到源头了,不容易啊.至此第一大步到此为止
    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }


     //...省略部分代码
    };
  }
复制代码

3.2.2 第二大步

调用ServiceMethod实际调用了HttpServiceMethod的invoke方法,我们直接看这个方法.

//HttpServiceMethod.java
@Override ReturnT invoke(Object[] args) {
    /*因为之前第一大步我们已经清楚,默认情况下callAdapter是ExecutorCallAdapterFactory适配器工厂下返回的,
    那么继续往下看适配器工厂找adapt
    */
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }
  
  //ExecutorCallAdapterFactory.java
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
     //...省略部分代码

      @Override
      public Call<Object> adapt(Call<Object> call) {
        //返回的Call实际上就是ExecutorCallbackCall
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
复制代码

Call的创建过程相对来说比较复杂,需要反复多浏览几遍,关键在于冷静下来根据线索去寻找.最后对Call的创建过程做一个总结.

  • 当调用代理对象的网络接口方法时,会触发InvocationHandler的invoke方法,最终返回一个Call.
  • 在invoke方法里面主要包含两大步骤.
    1. 第一大步,获取到网络接口方法对象(loadServiceMethod)
      • 检查是否有缓存,有直接返回,无,重新解析生成新的对象后,缓存再返回
        • 解析时获取适配器(CallAdapter),遍历适配器工厂集合,通过网络接口的返回类型(returnType)来获取对应适配器工厂,最终获得适配器(CallAdapter).
    2. 第二大步,调用ServiceMethod的invoke发送请求.
      • 同样利用获取到的CallAdapter调用adapt方法,返回一个Call对象.最后发送请求.

3.3 网络请求的发送过程

最后我们看ExecutorCallbackCall是如何发请求和回调的.

对应源码

static final class ExecutorCallbackCall<T> implements Call<T> {
    //初始化时设置的线程回调执行器
    final Executor callbackExecutor;
    //为OkHttpCall
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    
  //发送网络请求
    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

      delegate.enqueue(new Callback<T>() {//使用okhttpClient进行异步请求
        //网络回调成功
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                
                //主线程回调失败
                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);
            }
          });
        }
      });
    }

    //...省略部分代码
}
复制代码

最后老规矩,对网络请求的发送过程做一个小结.

通过enqueue方法,利用Okhttp发送网络请求,网络响应成功或失败通过回调执行器(MainThreadExecutor)分发到主线程执行.


由于本人技术有限,如有错误的地方,麻烦大家给我提出来,本人不胜感激,大家一起学习进步.

关注下面的标签,发现更多相似文章
评论