秒懂Retrofit2之CallAdapter

导读:本篇文章讲解 秒懂Retrofit2之CallAdapter,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

【版权申明】非商业目的注明出处可自由转载
博文地址:
出自:shusheng007

系列文章
秒懂的Retrofit2源码详解
用Retrofit+RxJava2封装优雅的网络请求框架
秒懂Retrofit2之Converter
秒懂Retrofit2之GsonConverter

概述

Retrofit2 已经成为Android开发网络请求当之无愧的扛把子了,我们很有必要对自己经常使用的东西有个深入的了解。

Retrofit2 中有两个非常精彩的设计:ConverterCallAdapter, 通过这两个接口,Retrofit的可扩展性被极大的增强了,用户可以根据需求自由扩展。在上一篇文章 秒懂Retrofit2之Converter中我们对Converter做了比较详细的解析,这篇文章就对Calladapter做一个比较深入的了解。

作用

Retrofit2 中有两个非常精彩的设计:ConverterCallAdapter, 这是两个接口,通过这两个接口,retrofit的可扩展性被极大的增强了,用户可以根据需求自由扩展。

假如有如下代码:其中UserPerson 是两个自定义类

    @POST
    Observable<List<User>>m1(@Body Person rBody);
    
    @POST
    Call<List<User>>m2(@Body Person rBody);

仔细观察方法m1和m2发现他们的返回类型有一定的区别,m1 的放回类型是Rxjava2 的 Observable<T> 而m2是Retrofit2 的Call<T>。这个类型就是由CallAdapter 决定的,例如Call<T> 类型就是通过CallAdapter将得到的。Retrofit2 的方法的返回值必须是泛型类型,例如Call<T>,通过调用CallAdapter里的 adapt()方法,将方法的返回值适配为类似Call<T>的样子,而在这个过程中又调用了ConverterresponseBodyConverter()方法,将htpp返回的ResponseBody类型的数据转换为Call<T>里面的 T

源码解析

我们先看一下CallAdapter的源码:

public interface CallAdapter<R, T> {
  //retrofit 方法的返回类型的泛型参数代表的类型,例如 方法的返回类型(returnType)为Call<User> ,那么responseType  为User
  Type responseType();
  //Returns an instance of {@code T} which delegates to {@code call}.
  T adapt(Call<R> call);

  abstract class Factory {
    //获得一个call adapter
    //returnType 为接口中方法的泛型返回类型例如 Call<User>
    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);

   //两个工具方法
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

接口很简单,里面仅有两个方法,responseType()adapt().
responseType() 是一个取值方法,使用它获得当前方法的响应类型。主要用途是检查我们定义的方法返回值里面那个泛型参数的类型是否正确,例如Call<User>是正确的,而Call<okhttp3.Response> 则是不正确的。
adapt() 负责适配

接口里面还有一个内部类Factory,我们就是通过这个factory里的get方法获得相应的Adapter的

使用机制

那么CallAdapter 在retrofit2中是如何发挥作用的呢,关键代码在HttpServiceMethod<ResponseT, ReturnT> 类中的invoke()方法中,程序每发起一个HTTP请求时,首先就会调用这个方法:

  //提交一个http请求,返回我们设定的类型的结果,例如Call<User>
  @Override ReturnT invoke(@Nullable Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<ResponseT>(requestFactory, args, callFactory, responseConverter));
  }

Retrofit2的方法之所以可以返回Call<T>是因为其有两个默认的CallAdapter实现,DefaultCallAdapterFactoryExecutorCallAdapterFactory, Retrofit2 会自动判断当前运行的平台,如果发现是Android平台则使用ExecutorCallAdapterFactory,其他情况使用另一个。

DefaultCallAdapterFactory

DefaultCallAdapterFactory 源码如下:

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }

    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return call;
      }
    };
  }
}

代码很简单,通过get获得一个CallAdapter。首先要求方法的返回值returnType的原始类型必须是Call类型,就是说returnType必须为Call<T>,然后返回一个Call<Object>数据。
这就决定了你声明方法时候必须是如下的形式:

@POST
Call<List<User>>m2(@Body Person rBody);

返回值类型必须是Call<Object>的形式,你说你想返回Rxjava2的Observerable,别闹,这个CallAdapter不认识这个东东。

ExecutorCallAdapterFactory

其实ExecutorCallAdapterFactory 应该是做Android开发的重点关注的,其与DefaultCallAdapterFactory 是一脉相承的,唯一的增强就是通过一个MainThreadExecutor 将结果回调切换到了UI线程上,让我们可以直接在结果回调中操作UI控件。

以下是MainThreadExecutor的源码,是不是有一种熟悉的味道

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }

ExecutorCallAdapterFactory 的源码如下:

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
       this.callbackExecutor = callbackExecutor;
  }

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
        final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    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>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                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);
            }
          });
        }
      });
    }
     ...

  }
}

从上面的源码中可以看到DefaultCallAdapterFactoryExecutorCallAdapterFactory唯一的区别就是在adapt()方法中返回的那个Call接口的实现类实例不一样。

 //DefaultCallAdapterFactory 里的实现方式
  @Override public Call<Object> adapt(Call<Object> call) {
     return call;
  }

  //ExecutorCallAdapterFactory 里的实现方式
  @Override public Call<Object> adapt(Call<Object> call) {
     return new ExecutorCallbackCall<>(callbackExecutor, call);
  }

我们就是在ExecutorCallbackCall 里面将结果回调切换到了UI线程。

理解了原理后,自定义一个CallAdapter就变的很容易了。 我们使用比较多的就是与Rxjava2结合的RxJava2CallAdapterFactory, 这个自定义的CallAdapter算是比较复杂的了,那是因为Rxjava2比较难于上手,其实实现原理还是那一套。就是不返回Call<T>, 转而返回Rxjava2自己的类,例如Onserverable<T>.

总结

可见一个设计优良的类库,会给用户很大的扩展空间,这一点我们应该多加学习。

最后,求关注,求点赞!有任何疑问可以评论留言,我会尽力回复的

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/14752.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!