Retrofit2源码解析
来源:互联网 发布:linux磁盘阵列 编辑:程序博客网 时间:2024/05/16 04:59
最近项目将网络框架换成Retrofit2.0.2,文中说的Retrofit都是指的Retrofit2这里要说明一下,毕竟和Retrofit1差别还是蛮大的,结合Okhttp,RxJava还是比较好用的,网上有很多前辈介绍过使用方法,本文是想研究一下Retrofit的源码。关于Retrofit的介绍可以查阅Retrofit的官方网站
直接进入主题:(注本文是结合RxJava介绍的,最好可以了解一下RxJava不了解也没有关系,大部分的思想是一样的)
Retrofit的基本使用
Retrofit使用是非常简单的,在上边的官网上介绍的也非常详细。但是为了后边的分析,还是把使用的代码贴在这儿:
一般在项目中会将需要请求网络方法写在一个接口中,如下:
public interface GitHubService { @GET("users/{user}/repos") Observable<List<Repo>> listRepos(@Path("user") String user); }
如果要使用Retrofit还需要构建Retrofit的对象:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();
主要就是配置baseUrl,ConverterFactory,CallAdapterFactory。这里用的是Gson,和RxJava所以相应的就是GsonConverterFactory,RxJavaCallAdaperFactory这个在后边的源码分析中会用到。
最后直接调用就可以了:
GitHubService service = retrofit.create(GitHubService.class);service.listRepos("octocat") .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(list->{ if(list!=null){ //TODO 取得数据后逻辑处理 } });
可以说,代码还是非常简洁的。用起来也很容易上手。
Retrofit工作流程
如上面的使用中我们可以看到:
1.通过Retrofit.Builder().build()构建Retrofit实例。
2.调用Retrofit的create()方法将生成接口GitHubService的实例。
3.调用GitHubService的listRepos()方法返回Observable<List<Repo>>
,这里的GitHubService实例实际上是个代理对象,这个下文再说。
下图是我整理的Retrofit运行时主要节点的时序图,当然不是所有的过程都反映出来了。
看不懂没关系,一步一步来,先看看Retrofit源码的构成:
简单的介绍一下
1.Call(接口)–向服务器发送请求并返回响应的调用
2.CallAdapter(接口)–Call的适配器,用来包装转换Call
3.CallAdapter.Factory(接口)–CallAdapter的工厂,通过get方法获取对应的CallAdapter
4.CallBack(接口)–Call的回调
5.Converter(接口)–数据转换器,将一个对象转化另外一个对象
6.Converter.Factory(抽象类) – 数据转换器Converter的工厂
responseBodyConverter – 将服务器返回的数据转化ResponseBody。
requestBodyConverter – 将GitHubService.listRepos()中的Body,Part等注解转换为RequestBody(),以便Okhttp请求的时候使用。
stringConverter – 将Field,FieldMap 值,Header,Path,Query,和QueryMap值转化为String,以便Okhttp请求的时候使用。
7.ServiceMethod 通过解析注解,传参,会将你的接口方法调用转化为一个 Call 对象。也就说对于每一个接口方法,他都会创建一个与之对应的 ServiceMethod
另外retrofit还有一个http包,都是用来定义 HTTP 请求的自定义注解。如果对注解不太熟悉可以看看我的ButterKnife源码剖析 关于注解的介绍。
回到上边步骤2,调用Retrofit的create()方法将生成接口GitHubService的实例:
GitHubService service = retrofit.create(GitHubService.class);
将GithubService.class作为参数,传入create(),然后又返回一个GithubService实例,看起来是不是很神奇。源码如下:
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety. public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(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 = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }
这里使用了动态代理,返回了一个 Proxy 代理类,调用GithubService(在自己的项目中是XXXService接口)接口中的任何方法都会调用 proxy 里的 invoke 方法。这个方法里边最重要的就是第23,24,25行代码。
1.构建ServiceMethod实例
先看第23行
ServiceMethod serviceMethod = loadServiceMethod(method);
通过loadServiceMethod方法获取ServiceMethod实例:
ServiceMethod loadServiceMethod(Method method) { ServiceMethod result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
第4行首先会先尝试从serviceMethodCache(类型Map<Method, ServiceMethod>
)中get,如果缓存中没有则构建一个ServiceMethod实例。接着看怎么构建ServiceMethod实例,ServiceMethod.java中源码:
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(); responseType = callAdapter.responseType(); if (responseType == Response.class || responseType == okhttp3.Response.class) { throw methodError("'" + Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } responseConverter = createResponseConverter(); for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } if (httpMethod == null) { throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.)."); } if (!hasBody) { if (isMultipart) { throw methodError( "Multipart can only be specified on HTTP methods with request body (e.g., @POST)."); } if (isFormEncoded) { throw methodError("FormUrlEncoded can only be specified on HTTP methods with " + "request body (e.g., @POST)."); } } int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0; p < parameterCount; p++) { Type parameterType = parameterTypes[p]; if (Utils.hasUnresolvableType(parameterType)) { throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s", parameterType); } Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; if (parameterAnnotations == null) { throw parameterError(p, "No Retrofit annotation found."); } parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); } if (relativeUrl == null && !gotUrl) { throw methodError("Missing either @%s URL or @Url parameter.", httpMethod); } if (!isFormEncoded && !isMultipart && !hasBody && gotBody) { throw methodError("Non-body HTTP method cannot contain @Body."); } if (isFormEncoded && !gotField) { throw methodError("Form-encoded method must contain at least one @Field."); } if (isMultipart && !gotPart) { throw methodError("Multipart method must contain at least one @Part."); } return new ServiceMethod<>(this); }
使用Builder模式来构建serviceMethod实例,将retrofit实例,和invoke的方法作为参数来初始化。第10行通过调用createCallAdapter()创建CallAdapter实例callAdapter。
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 { 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); } }
看第11行,获取到了,接口方法中使用的注解,在我们本文中的GithubService的listRepos的注解就是@Get();第13行会通过调用Retrofit的callAdapter()方法来返回CallAdapter实例:
Retrofit.java文件中:
/** * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain * #callAdapterFactories() factories}. * * @throws IllegalArgumentException if no call adapter available for {@code type}. */ public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } /** * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain * #callAdapterFactories() factories} except {@code skipPast}. * * @throws IllegalArgumentException if no call adapter available for {@code type}. */ public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { checkNotNull(returnType, "returnType == null"); checkNotNull(annotations, "annotations == null"); int start = adapterFactories.indexOf(skipPast) + 1; for (int i = start, count = adapterFactories.size(); i < count; i++) { CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } StringBuilder builder = new StringBuilder("Could not locate call adapter for ") .append(returnType) .append(".\n"); if (skipPast != null) { builder.append(" Skipped:"); for (int i = 0; i < start; i++) { builder.append("\n * ").append(adapterFactories.get(i).getClass().getName()); } builder.append('\n'); } builder.append(" Tried:"); for (int i = start, count = adapterFactories.size(); i < count; i++) { builder.append("\n * ").append(adapterFactories.get(i).getClass().getName()); } throw new IllegalArgumentException(builder.toString()); }
真的实现是在Retrofit.java中的nextCallAdapter()方法中实现的。上边代码第25行,adapterFactories是一个缓存CallAdapter.Factory的list,我们在构建Retrofit实例时,曾经设置过addCallAdapterFactory(RxJavaCallAdapterFactory.create()),也就意味着adapterFactories.get(i)将获得到RxJavaCallAdapterFactory,然后会执行其get()方法。
RxJavaCallAdapterFactory.java文件中:
@Override public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { 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) { // Add Completable-converter wrapper from a separate class. This defers classloading such that // regular Observable operation can be leveraged without relying on this unstable RxJava API. // Note that this has to be done separately since Completable doesn't have a parametrized // type. return CompletableHelper.createCallAdapter(scheduler); } CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler); if (isSingle) { // Add Single-converter wrapper from a separate class. This defers classloading such that // regular Observable operation can be leveraged without relying on this unstable RxJava API. return SingleHelper.makeSingle(callAdapter); } return callAdapter; }
正常情况下,会执行到第27行,通过getCallAdapter方法,获得Observable泛型的CallAdapter,继续跟进去看看:
private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) { Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType); Class<?> rawObservableType = getRawType(observableType); if (rawObservableType == Response.class) { if (!(observableType instanceof ParameterizedType)) { throw new IllegalStateException("Response must be parameterized" + " as Response<Foo> or Response<? extends Foo>"); } Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType); return new ResponseCallAdapter(responseType, scheduler); } if (rawObservableType == Result.class) { if (!(observableType instanceof ParameterizedType)) { throw new IllegalStateException("Result must be parameterized" + " as Result<Foo> or Result<? extends Foo>"); } Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType); return new ResultCallAdapter(responseType, scheduler); } return new SimpleCallAdapter(observableType, scheduler); }
第3行会getRawType(observableType)会返回Observable具体类型,例如本例中,
public interface GitHubService { @GET("users/{user}/repos") Observable<List<Repo>> listRepos(@Path("user") String user); }
返回值是Observable<List<Repo>>
那么getRawType(observableType)将得到List.class,这样程序将执行第22行,将返回一个SimpleCallAdapter实例,那么它就是CallAdapter的真正实现。
回到ServiceMethod的build()方法中,继续执行第18行responseConverter = createResponseConverter();过程也和createCallAdapter差不多,也是使用工厂模式,通过get()方法获得Converter的真正实现,篇幅所限就不一步一步的跟了,本例使用的是Gson,所以Converter得实现是GsonResponseBodyConverter。之后就是解析注解,参数等,这样ServiceMethod已经构建好了。
生成OkHttpCall
回到Retrofit动态代理invoke方法中,第二步就是生成Call的实例了,目前Retrofit的默认使用的是OkhttpCall。其是OkHttp的包装类,所有OkHttp需要的参数都在该类中找到。
adapt Call
第三步执行serviceMethod.callAdapter.adapt(okHttpCall),通过之前的分析,serviceMethod.callAdapter真正的实现是SimpleCallAdapter,那么自然也是执行的它的adapt()方法。为了证实这个,可以debug一下就知道了。
RxJavaCallAdapterFactory.SimpleCallAdapter.adapt():
@Override public <R> Observable<R> adapt(Call<R> call) { Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) .lift(OperatorMapResponseToBodyOrError.<R>instance()); if (scheduler != null) { return observable.subscribeOn(scheduler); } return observable; } }
其返回类型Observable,也就是我们需要的结果,还记得我们是怎么使用的RxJava的吗?
service.listRepos("octocat") .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(list->{ if(list!=null){ //TODO 取得数据后逻辑处理 } });
看代码service.listRepos(“octocat”)应该是一个Observable,而刚刚分析的,service.listRepos(“octocat”)确实会返回一个Observable,有了这个Observable之后,我们就可以通过subscribeOn给他指定运行线程,这样像网络请求耗时操作就不会再UI线程中运行,从而达到异步的目的,然后通过observeOn()将线程切回UI线程,当Okhttp请求完数据并进行相应的convert之后,就可以在UI处理相应的逻辑。
回到adapt方法,第2行创建Observable,而new CallOnSubscribe<>(call)生成了一个OnSubscribe()的实例,而OnSubscribe继承自Action1,其只包含一个call()方法,而这个call是在CallOnSubscribe中实现:
static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> { private final Call<T> originalCall; CallOnSubscribe(Call<T> originalCall) { this.originalCall = originalCall; } @Override public void call(final Subscriber<? super Response<T>> subscriber) { // Since Call is a one-shot type, clone it for each new subscriber. Call<T> call = originalCall.clone(); // Wrap the call in a helper which handles both unsubscription and backpressure. RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber); subscriber.add(requestArbiter); subscriber.setProducer(requestArbiter); } }
首先clone了一份Call,然后生成了RequestArbiter,他继承自AtomicBoolean,实现了Subscription, Producer接口,Producer只有一个request方法;一般实现该接口的类,都会包含一个Subscriber对象和一个待处理的数据:
static final class RequestArbiter<T> extends AtomicBoolean implements Subscription, Producer { private final Call<T> call; private final Subscriber<? super Response<T>> subscriber; RequestArbiter(Call<T> call, Subscriber<? super Response<T>> subscriber) { this.call = call; this.subscriber = subscriber; } @Override public void request(long n) { if (n < 0) throw new IllegalArgumentException("n < 0: " + n); if (n == 0) return; // Nothing to do when requesting 0. if (!compareAndSet(false, true)) return; // Request was already triggered. try { Response<T> response = call.execute(); if (!subscriber.isUnsubscribed()) { subscriber.onNext(response); } } catch (Throwable t) { Exceptions.throwIfFatal(t); if (!subscriber.isUnsubscribed()) { subscriber.onError(t); } return; } if (!subscriber.isUnsubscribed()) { subscriber.onCompleted(); } } @Override public void unsubscribe() { call.cancel(); } @Override public boolean isUnsubscribed() { return call.isCanceled(); } }
那么看看request()方法到底干了什么?第16行代码call.execute()最终将执行okhttp的execute(),为什么这里会同步请求数据呢,还记得之前我们把耗时操作切换到子线程中吗?既然已经不是在UI线程了,这里就可以使用同步获取response数据了。在获取到response后就通过执行subscriber.onNext(response);这样subscribe过Observable的subscriber都可以收到数据了。而因为我们设置过observeOn(AndroidSchedulers.mainThread()),所以当我们接受到数据的时候,已经是在UI线程中了,所以就可以做后续的逻辑处理了。
总结:Retrofit 的代码并不是很多,其底层网络通信时交由 OkHttp 3来完成的,但是Retrofit运用了大量的设计模式,代码逻辑很清晰。没事的时候,不妨研究研究,毕竟是Jake Wharton大神的杰作。
- Retrofit2源码解析
- Retrofit2 源码解析
- Retrofit2.0源码解析
- Retrofit2 源码解析
- Retrofit2 源码解析
- Retrofit2 源码解析
- Retrofit2 源码解析
- Retrofit2 源码解析
- Retrofit2 源码解析
- Retrofit2.1源码解析
- Retrofit2 源码解析
- Retrofit2.0源码解析
- Retrofit2 源码解析
- retrofit2源码解析
- Retrofit2.0源码解析
- Retrofit2 源码解析
- Retrofit2源码解析
- Retrofit2.0源码解析
- fopen打开文件模式rb和rb+有什么区别
- Django中新版本变动和版本不同的各种坑 (持续更新)
- Mina自定义协议-实现数据交互
- android6.0之下apk运行正常,6.0之后突然一直报需要某个权限且apk崩溃
- Centos6.5使用yum安装mysql——快速上手必备
- Retrofit2源码解析
- 帧缓冲 Frame Buffer
- leetcode---Compare Version Numbers
- ardupilot在Ubuntu12.04.5-32bit-x86环境下的编译,简易版编译环境搭建,实际使用
- php 从文件中读取匹配条件字符串
- 【QTP】FSO读取/写txt文本乱码解决方法
- 数据库之mybook=mrcbook——书签的应用
- Node.js背后的V8引擎优化技术
- 关于图像处理