以下都是本人收集和总结的内容:
1. 什么是Retrofit
Retrofit是一个 RESTful 的 HTTP 网络请求框架的封装。注意这里并没有说它是网络请求框架,主要原因在于网络请求的工作并不是 Retrofit来完成的。Retrofit2.0 开始内置 OkHttp
640.png
我们的应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数、Header、Url 等信息,之后由OkHttp完成后续的请求操作,在服务端返回数据之后,OkHttp将原始的结果交给Retrofit,后者根据用户的需求对结果进行解析的过程。讲到这里,你就会发现所谓Retrofit,其实就是 Retrofitting OkHttp 了。
2. 如何实现Retrofit
2.1.定义请求接口
public interface GitHubService {
@GET("/users/{user}/repos")
List<Repo> listRepos(@Path("user") String user);
}
接口当中的 listRepos 方法,就是我们想要访问的 api 了, 如下:
https://api.github.com/users/{user}/repos
2.2.通过retrofit生成一个刚才定义接口的实现类
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
2.3.通过接口直接进行请求
其中,在发起请求时, {user} 会被替换为方法的第一个参数 octocat.
Call<List<Repo>> repos= service.listRepos("octocat");
发请求的代码就像前面这一句,返回的 repos其实并不是真正的数据结果,它更像一条指令,你可以在合适的时机去执行它:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
//执行
Call<List<Repo>> repos = service.listRepos("octocat");
List<Repo> data = repos.execute();
2.4.参数的配置
发请求时,需要传入参数,Retrofit 通过注解的形式令 Http 请求的参数变得更加直接,而且类型安全。
2.4.1 Query & QueryMap
@GET("/list")
Call<ResponseBody> list(@Query("page") int page);
Query 其实就是 Url 中 ‘?’ 后面的 key-value,比如:
这里的tn=56060048_4_pg 就是一个 Query,而我们在配置它的时候只需要在接口方法中增加一个参数
这时候你肯定想,如果我有很多个 Query,多参数的版本的 QueryMap 横空出世了,使用方法如下
@GET("/list")
Call<ResponseBody> list(@QueryMap Map<String, String> options);
2.4.2 Field & FieldMap
其实我们用 POST 的场景相对较多,绝大多数的服务端接口都需要做加密、鉴权和校验,GET显然不能很好的满足这个需求。使用 POST 提交表单的场景就更是刚需了,怎么提呢?
@FormUrlEncoded
@POST("/")
Call<ResponseBody> example( @Field("name") String name,
@Field("occupation") String occupation);
其实也很简单,我们只需要定义上面的接口就可以了,我们用 Field声明了表单的项,这样提交表单就跟普通的函数调用一样简单直接了。
同样多版本版本FieldMap,使用方式和QueryMap差不多,不讲了
2.4.3 Part & PartMap
这个是用来上传文件的
public interface FileUploadService {
@Multipart
@POST("upload")
Call<ResponseBody> upload(@Part("description") RequestBody description,
@Part MultipartBody.Part file);
}
如果你需要上传文件,和我们前面的做法类似,定义一个接口方法,需要注意的是,这个方法不再有 @FormUrlEncoded 这个注解,而换成了 @Multipart,后面只需要在参数中增加 Part
就可以了。也许你会问,这里的 Part 和 Field 究竟有什么区别,其实从功能上讲,无非就是客户端向服务端发起请求携带参数的方式不同,并且前者可以携带的参数类型更加丰富,包括数据流。也正是因为这一点,我们可以通过这种方式来上传文件,下面我们就给出这个接口的使用方法:
上传文件.png
在实验时,我上传了一个只包含一行文字的文件:
Visit me: http://www.println.net
那么我们去服务端看下我们的请求是什么样的:
HEADERS
FORM/POST PARAMETERS
description: This is a description
RAW BODY
我们看到,我们上传的文件的内容出现在请求当中了。如果你需要上传多个文件,就声明多个 Part参数,或者试试 PartMap
2.5 Converter,让你的入参和返回类型丰富起来
2.5.1 RequestBodyConverter
2.4.3 当中,我为大家展示了如何用 Retrofit上传文件,这个上传的过程其实。。还是有那么点儿不够简练,我们只是要提供一个文件用于上传,可我们前后构造了三个对象:
fdfdf.png
天哪,肯定是哪里出了问题。实际上,Retrofit 允许我们自己定义入参和返回的类型,不过,如果这些类型比较特别,我们还需要准备相应的 Converter,也正是因为 Converter 的存在,Retrofit 在入参和返回类型上表现得非常灵活。
下面我们把刚才的 Service 代码稍作修改:
public interface FileUploadService {
@Multipart
@POST("upload")
Call<ResponseBody> upload(@Part("description") RequestBody description,
//注意这里的参数 "aFile" 之前是在创建 MultipartBody.Part 的时候传入的
@Part("aFile") File file);
}
现在我们把入参类型改成了我们熟悉的 File,如果你就这么拿去发请求,服务端收到的结果会让你哭了的。。。
RAW BODY
服务端收到了一个文件的路径,这明显是 Retrofit 在发现自己收到的实际入参是个 File时,不知道该怎么办,情急之下给 toString了,而且还是个 JsonString(后来查证原来是使用了 GsonRequestBodyConverter。。)。
接下来我们就自己实现一个 FileRequestBodyConverter
static class FileRequestBodyConverterFactory extends Converter.Factory {
@Override
public Converter<File, RequestBody> requestBodyConverter(Type type, Annotation[]
parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new FileRequestBodyConverter();
}
}
static class FileRequestBodyConverter implements Converter<File, RequestBody> {
@Override
public RequestBody convert(File file) throws IOException {
return RequestBody.create(MediaType.parse("application/otcet-stream"), file);
}
}
在创建 Retrofit 的时候记得配置上它:
addConverterFactory(new FileRequestBodyConverterFactory())
这样,我们的文件内容就能上传了。来,看下结果吧:
RAW BODY
文件内容成功上传了.
2.5.2 ResponseBodyConverter
前面我们为大家简单示例了如何自定义 RequestBodyConverter,对应的,Retrofit 也支持自定义 ResponseBodyConverter。
我们再来看下我们定义的接口:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
返回值的类型为 List<Repo>,而我们直接拿到的原始返回肯定就是字符串(或者字节流),那么这个返回值类型是怎么来的呢?首先说明的一点是,GitHub 的这个 api 返回的是 Json 字符串,也就是说,我们需要使用 Json 反序列化得到 List<Repo>,这其中用到的其实是 GsonResponseBodyConverter。
问题来了,如果请求得到的 Json 字符串与返回值类型不对应,比如:
接口返回的 Json 字符串:
{"err":0, "content":"This is a content.", "message":"OK"}
返回值类型
class Result {
int code;//等价于 err
String body;//等价于 content
String msg;//等价于 message
}
这种情况下, Gson 就是再牛逼,也只能默默无语俩眼泪了,它哪儿知道字段的映射关系怎么这么任性啊。好,现在让我们自定义一个 Converter 来解决这个问题吧!
GsonConverter .png当然,别忘了在构造 Retrofit 的时候添加这个 Converter,这样我们就能够愉快的让接口返回 Result 对象了。
注意!!Retrofit 在选择合适的 Converter 时,主要依赖于需要转换的对象类型,在添加 Converter 时,注意 Converter 支持的类型的包含关系以及其顺序。
3.结合Retrofit源码深度学习
retrofit的最大特点就是解耦,要解耦就需要大量的设计模式
精简流程图
Retrofit流程图.png
举个列子,跟随他进入主题
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
//执行
Call<List<Repo>> repos = service.listRepos("octocat");
List<Repo> data = repos.execute();
3.1首先通过@GET来标识这个接口是一个GET请求。那么看一下这个GET注解的定义。
@Documented
//@Target表示Annotation可用在什么地方。
//METHOD:方法声明
@Target(METHOD)
//@Retention表示在什么级别保存该注解信息
//RUNTIME:VM会在运行时保留注解,这时可以通过反射读取注解信息
@Retention(RUNTIME)
public @interface GET {
String value() default "";
}
3.2 接下来看一下是如何创建Retrofit对象的。
public final class Retrofit {
......代码省略.......
//对平台的支持
private Platform platform;
//发起请求OKHttp3的Client工厂
private okhttp3.Call.Factory callFactory;
//OKHttp2的HttpUrl对象,也就是将我们传入的baseUrl字符串包装成HttpUrl
private HttpUrl baseUrl;
//转换器工厂集合,retrofit可以插入多个转化器,例如:Gson,Jackson等等
private List<Converter.Factory> converterFactories = new ArrayList<>();
//用于发起请求和接收响应的Call适配器工厂集合,
//Retrofit对RxJava的支持就是通过在该集合中添加RxJavaCallAdapterFactory,
//而RxJavaCallAdapterFactory正是继承自CallAdapter.Factory
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
//Executor并发框架,用于对请求后响应结果的回调执行
private Executor callbackExecutor;
//是否需要立即生效
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
//对属性的配置
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//默认添加ExecutorCallAdapterFactory ,先记住~~~~~~
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
......代码省略.......
}
Builder中的Platform.get()做什么了?我们继续点击查看:
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
//通过findPlatform方法我们可以看出Retrofit支持三个平台
private static Platform findPlatform() {
try {
//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) {
}
try {
//IOS,这里的IOS指的是RoboVM。
//RoboVM它是一种可以在iOS设备上运行Java应用程序的技术,这种技术主要还是用于在游戏开发中。
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
//默认为null,子类重写赋值
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
}
当前平台为Android平台之后返回一个Android对象,这个Android类是Platform中的一个静态内部类。我们看看他做了什么
static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
//重写父类,返回的Handler对象
return new MainThreadExecutor();
}
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
//网络请求时分析ExecutorCallAdapterFactory做了什么
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
3.3 接下来直入重点,Retrofit对象的创建OK以后,便通过Reetrofit中的create方法创建一个我们请求接口,其实创建的一个代理对象了,这里涉及点儿 Java 的动态代理的知识,直接来看create代码:
public final class Retrofit {
......代码省略.......
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//这里返回一个service的代理对象
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, 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);
}
//每一个接口最终初始化一个serviceMethod
ServiceMethod serviceMethod = loadServiceMethod(method);
//并且Retrofit 与 Okhttp 完全耦合
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//发送请求,并且解析服务端返回的结果
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
//这个方法通过反射获取我们创建service接口中所有的接口方法,然后根据接口方法和当前的
//retrofit对象来获得ServiceMethod并且以接口方法作为Key,
//ServiceMethod作为值添加到serviceMethodCache缓存中
//下次便可以通过接口方法直接获取ServiceMethod
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//初始化ServiceMethod,并且执行serviceMethod.callAdapter
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
......代码省略.......
}
总结下,当我们通过代理类(也就是我们调用create方法后返回的service)调用我们所创建的接口方法时。InvocationHandler中的invoke方法将会被调用。在invoke方法中由于method.getDeclaringClass()获取到的是一个接口,并不是Object类,所以第一个条件不成立。而在Android平台下platform.isDefaultMethod(method)返回的为false,所以这个条件也不成立。之后通过loadServiceMethod方法来获取ServiceMethod。最后调用ServiceMethod中callAdapter的adapt方法。而ServiceMethod中的callAdapter属性是通过ServiceMethod中createCallAdapter方法所创建。在createCallAdapter中实际上是调用了Retrofit中的callAdapter方法来对ServiceMethod中的callAdapter进行初始化。
简单的说,在我们调用 GitHubService.listRepos 时,实际上调用的是这里的InvocationHandler.invoke 方法~~
3.4 下面再看一下ServiceMethod中的callAdapter方法如何执行,
final class ServiceMethod<T> {
final Retrofit retrofit;
final Method method;
final Annotation[] methodAnnotations;
final Annotation[][] parameterAnnotationsArray;
final Type[] parameterTypes;
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
callAdapter = createCallAdapter();
......省略代码......
return new ServiceMethod<>(this);
}
private CallAdapter<?> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//注意这里调用Retrofit的callAdapter
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
}
接下来查看Retrofit的callAdapter做了什么
public final class Retrofit {
.......省略代码.........
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
//通过遍历adapterFactories并根据我们的接口方法所中返回值类型来获取相应的适配器callAdapter。
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
.......省略代码.........
}
总结:通过遍历adapterFactories并根据我们的接口方法所中返回值类型来获取相应的适配器callAdapter,如果我们想返回的是RxJava中Observable对象, 那我们添加了RxJavaCallAdapterFactory,那么返回的就是RxJavaCallAdapter。如果没有添加那么此处的adapter为null,便会抛出异常。在正是通过这种适配器模式完成了对RxJava的完美结合。
Call<List<Repo>> repos = service.listRepos("octocat");
List<Repo> data = repos.execute();
service.listRepos("octocat");这个方法到底怎么执行的我们上面还遗留了一个ExecutorCallAdapterFactory方法接下来我们一步一步研究它
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
//get方法返回一个CallAdapter对象,
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
//adapt方法返回ExecutorCallbackCall对象,它实现了Retrofit中的Call接口
//其实就是InvocationHandler.invoke 那个callAdapter的实现类
@Override public <R> Call<R> adapt(Call<R> 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) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(final 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(call, new IOException("Canceled"));
} else {
callback.onResponse(call, response);
}
}
});
}
@Override public void onFailure(final Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(call, t);
}
});
}
});
}
......
}
从ExecutorCallAdapterFactory类中可看出通过get方法返回一个CallAdapter对象,从对CallAdapter的实现中可以看出在CallAdapter中的adapt方法返回的是ExecutorCallbackCall对象。它实现了Retrofit中的Call接口。到这里我们也就明白了,当通过代理调用我们创建的接口方法中所返回的Call对象就是这个ExecutorCallbackCall。当我们通过call.enqueue来完成网络请求操作实际上就是调用ExecutorCallbackCall中的enqueue方法。在ExecutorCallbackCall中enqueue又将网络请求委托给OkHttpCall去执行。而这个OkHttpCall正是我们在Retrofit的create方法中所创建的OkHttpCall。由于OKHttp的CallBack接口中的onResponse和onFailure是在子线程中执行的,所以在这时候又通过callbackExecutor将CallBack的onResponse和onFailure切换到主线程中执行。
有了上面分析后我们知道repos.execute()其实就是一个 OkHttpCall 实例,execute 就是要发起网络请求
那么点进去看看Call 的接口:
public interface Call<T> extends Cloneable {
//同步发起请求
Response<T> execute() throws IOException;
//异步发起请求,结果通过回调返回
void enqueue(Callback<T> callback);
boolean isExecuted();
void cancel();
boolean isCanceled();
Call<T> clone();
//返回原始请求
Request request();
}
然后在继续查看OkHttpCall
final class OkHttpCall<T> implements Call<T> {
@Override public Response<T> execute() throws IOException {
//这个call 是 Okhttp的call,本质对okhttpcall做了一层封装
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 {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//发送请求,并解析结果
return parseResponse(call.execute());
}
.......省略代码.........
}
我们看到 OkHttpCall 其实也是封装了 okhttp3.Call,在这个方法中,我们通过 okhttp3.Call 发起了进攻,额,发起了请求。有关 OkHttp 的内容,我在这里就不再展开了。
parseResponse 主要完成了由 okhttp3.Response 向 retrofit.Response 的转换,同时也处理了对原始返回的解析:
final class OkHttpCall<T> implements Call<T> {
......省略代码.........
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
//略掉一些代码
try {
//在这里完成了原始 Response 的解析,T 就是我们想要的结果,
//比如GitHubService.listRepos 的 List<Repo>
T body = serviceMethod.toResponse(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.5 结果适配,你是不是想用 RxJava?
前面我们已经提到过 CallAdapter的事儿,默认情况下,它并不会对 OkHttpCall 实例做任何处理:
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
... 毫不留情的省略一些代码 ...
return new CallAdapter<Call<?>>() {
... 省略一些代码 ...
@Override
public <R> Call<R> adapt(Call<R> call) {
//看这里,直接把传入的 call 返回了
return call;
}};
}
}
现在的需求是,我想要接入 RxJava,让接口的返回结果改为 Observable:
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Observable<List<Contributor>> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
Retrofit 的开发者们早就想到了这个问题,并且为我们提供了相应的 Adapter,只需在构造 Retrofit时,添加它:
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
这样我们的接口就可以以 RxJava 的方式工作了。
接着我们搞清楚 RxJavaCallAdapterFactory 是怎么工作的,首先让我们来看下 CallAdapter
的接口:
public interface CallAdapter<T> {
//返回http解析后的类型,需注意这个类型并不是接口返回的类型,而是
//接口返回类型中泛型参数的实参
Type responseType();
//T 是我们需要转换成接口返回的类型。参数call 其实最初就是okhttpcall的实例
//在这里T 其实是rxjava 支持的类型 ,比如 observable
<R> T adapt(Call<R> call);
//我们需要将Factory的子类对应的实例在构造 retrofit 时添加到其中
abstract class Factory {
//根据接口的返回类型(observable<T>)。注释类型等等来判断是否当前adapter 支持的类型,不是则返回null
public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
//获取指定index的泛型参数的上限,比如对于
//map <string, ? extends number >, index 为1 时的参数上限是number
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
//获取原始类型,比如List<String> 返回list.class 这里传入的type情况
//可能比较复杂,不能直接当做class 去做判断,这个方法在判断类型是否
//为支持的类型时经常用到
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
代码中做了较为详细的注释,简单来说,我们只需要实现 CallAdapter 类来提供具体的适配逻辑,并实现相应的 Factory,用来将当前的 CallAdapter注册到 Retrofit 当中,并在 Factory.get方法中根据类型来返回当前的 CallAdapter 即可(如果对这个方面或者逻辑混乱的话,可以把3.3和3.4的流程在走一遍你就会明白 了)。知道了这些,我们再来看 RxJavaCallAdapterFactory:
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
.......省略代码.........
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//下面代码主要判断returntype 是否为rxjava 支持的类型
Class<?> rawType = getRawType(returnType);
String canonicalName = rawType.getCanonicalName();
boolean isSingle = "rx.Single".equals(canonicalName);
boolean isCompletable = "rx.Completable".equals(canonicalName);
if (rawType != Observable.class && !isSingle && !isCompletable) {
return null;
}
if (!isCompletable && !(returnType instanceof ParameterizedType)) {
String name = isSingle ? "Single" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + "<Foo> or " + name + "<? extends Foo>");
}
if (isCompletable) {
return CompletableHelper.createCallAdapter(scheduler);
}
CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);
if (isSingle) {
return SingleHelper.makeSingle(callAdapter);
}
return callAdapter;
}
static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {
private final Type responseType;
private final Scheduler scheduler;
SimpleCallAdapter(Type responseType, Scheduler scheduler) {
this.responseType = responseType;
this.scheduler = scheduler;
}
@Override public Type responseType() {
return responseType;
}
@Override public <R> Observable<R> adapt(Call<R> call) {
在这里创建需作为返回值的 observable 实例,并持有call 的实例
当observable.subscribe 触发时,call.execute 将会调用
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
.lift(OperatorMapResponseToBodyOrError.<R>instance());
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
}
.......省略代码.........
}
至此,Retrofit 大部分结构源码有了新的认知。
网友评论