Retrofit2实现源码分析
来源:互联网 发布:程序员团队名称大全 编辑:程序博客网 时间:2024/06/04 15:54
最近研究Retrofit2+RxJava实现网络请求及数据集处理,一部分的知识点就在Retrofit2,为了更好的理解代码,本人决定分析下Retrofit2源码,既然是分析源码就得带着目的去分析,那么说说本文要解决的问题吧,先看代码来说明
Retrofit retrofit = new Retrofit.Builder() .client(new OkHttpClient()) .baseUrl(API_URL) .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io())) .addConverterFactory(GsonConverterFactory.create()) .build();ZhuanLanApi api = retrofit.create(ZhuanLanApi.class);Call<ZhuanLanAuthor> call = api.getAuthor("qinchao");call.enqueue(new Callback<ZhuanLanAuthor>() { @Override public void onResponse(Call<ZhuanLanAuthor> call, Response<ZhuanLanAuthor> response) { System.out.println(response.body().getName()); } @Override public void onFailure(Call<ZhuanLanAuthor> call, Throwable t) { }});
以上代码就是单独使用Retrofit2的基本方式,在写该代码时,我有几个疑惑,先列举吧。
疑惑1: call.enqueue是怎么发起网络请求的,和Okhttp3发起的网络请求为什么这么相似疑惑2: 创建retrofit对象时client函数传的OkHttpClient对象有何作用疑惑3: addCallAdapterFactory函数传参有起到什么作用疑惑4: addConverterFactory函数传参起到什么作用
下面就来解决这些疑惑
1、Retrofit2和OkHttp3的关系
实际上Retrofit2是用来解决Okhttp3用法复杂的问题的,先看看用OkHttp3实现一个异步网络请求的代码
String url = "https://www.baidu.com/";OkHttpClient okHttpClient = new OkHttpClient();MediaType JSON = MediaType.parse("application/json;charset=utf-8");RequestBody body = RequestBody.create(JSON, "{'name':'yjing','age':'12'}");Request request = new Request.Builder() .post(body) .url(url) .build();Call call = okHttpClient.newCall(request);call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { System.out.println("我是异步线程,线程Id为:" + Thread.currentThread().getId()); }});
注意,这里只是举个例子,传的参数是没有意义的,从代码可以看出OkHttp3使用太复杂,每次调用都得配置手动配置参数,而Retrofit2就是对OkHttp3进行了封装,使得能够通过调用一个Java方法来发起网络请求,网络请求实际上还是由OkHttp3完成的,Retrofit2只是将Java方法反射成为对应的网络请求。
由OkHttp3的使用代码可知,使用OkHttp3发起网路请求使通过Call对象来完成的,而创建Call实例对象,需要OkHttpClient对象和Request对象(这里需要注意)。
2、Retrofit2框架结构说明
在对Retrofit2源码进行解析之前,先说说其框架结构
这里的接口和类并不多
Converter:负责转换网络请求返回数据为对应格式数据的接口,其中GsonConverterFactory共厂类生产的GsonRequestBodyConverter类就是该接口的实现CallAdapter:负者决定retrofit.create()返回参数的接口,DefaultCallAdapterFactory以及RxJavaCallAdapterFactory连个工厂类生产的类都是该接口的实现ServiceMethod:这个类比较核心,几乎保存了一个API请求所有需要的数据,OkHttpCall需要从ServiceMethod中获得一个Request对象,然后得到Response后,还需要传入ServiceMethod用对应的Converter对象转将Response数据换成数据格式Retrofit:生成Retrofit对象,并初始化上面的几个接口实现类或ServiceMethod类对象
3、Retrofit类介绍
上面有代码说明Retrofit对象的初始化操作,这里为了方便说明再贴一次
Retrofit retrofit = new Retrofit.Builder() .client(new OkHttpClient()) .baseUrl(API_URL) .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io())) .addConverterFactory(GsonConverterFactory.create()) .build();ZhuanLanApi api = retrofit.create(ZhuanLanApi.class);
通过build的一系列方法,完成了在Retrofit对象中实例化Convertor对应工厂类、CallAdapter对应工厂类以及OkHttpClient对象的初始化。
然后调用create方法
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); } });}
这里的create方法中使用了动态代理,作用是当调用对应service方法时,会执行到动态代理代码中来,并且传入service对应方法反射对象以及方法参数。而动态代理方法核心是最后三行代码,其中loadServiceMethod方法会实例化一个ServiceMethod对象,并实例化ServiceMethod对象中的一下几个关键变量
下面先在三小节说说ServiceMethod方法的关键点
3、ServiceMethod类的关键点
ServiceMethod中有callAdapter变量、responseConverter变量、toRequest方法、toResponse方法这几个关键点。
callAdapter变量
根据是否有调用addCallAdapterFactory方法来实例化,例如如果调用了addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))则根据该工厂类创建SimpleCallAdapter(这里只是列举了该工厂类能生产的其中一种)对象
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<R> observable = Observable.create(new CallOnSubscribe<>(call)) // .lift(OperatorMapResponseToBodyOrError.<R>instance()); if (scheduler != null) { return observable.subscribeOn(scheduler); } return observable; } }
如果没有调用addCallAdapterFactory方法则使用一下默认工厂类生成的CallAdapter对象。
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<Call<?>>() { @Override public Type responseType() { return responseType; } @Override public <R> Call<R> adapt(Call<R> call) { return call; } }; }}
这里一定熬注意两种CallAdapter对象的adapt方法的差异,不同的CallAdapterFactory生产的CallAdapter类,其adapt方法的返回参数不一样,DefaultCallAdapterFactory 对应的返回参数是Call,而SimpleCallAdapter 对应的返回参数是Observable。
responseConverter变量
该变量负责根据对应规则对Response数据进行格式转化,在Retrofit类的nextResponseBodyConverter方法中可以看到,当有调用addConverterFactory(GsonConverterFactory.create())使用GsonConverterFactory或其它的工厂类生产的转换器,从代码中可以看出当添加多个工厂类时,使用第一个工厂类生产的转换器。
for (int i = start, count = converterFactories.size(); i < count; i++) { Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<ResponseBody, T>) converter; }}
然后我们来看看GsonConverterFactory工厂类生产的对象
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> { private final Gson gson; private final TypeAdapter<T> adapter; GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) { this.gson = gson; this.adapter = adapter; } @Override public T convert(ResponseBody value) throws IOException { JsonReader jsonReader = gson.newJsonReader(value.charStream()); try { return adapter.read(jsonReader); } finally { value.close(); } }}
GsonResponseBodyConverter的convert方法会将ResponseBody 值转化为对应Java方法的返回参数T类型,如下面的方法则转化为ZhuanLanAuthor类型(解决疑惑4)。
Call<ZhuanLanAuthor> getAuthor(@Path("user") String user);
toResponse
T toResponse(ResponseBody body) throws IOException { return responseConverter.convert(body);}
这个方法将body数据转化为对应参数数据。
toRequest
/** Builds an HTTP request from method arguments. */Request toRequest(Object... args) throws IOException { RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types. ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers; int argumentCount = args != null ? args.length : 0; if (argumentCount != handlers.length) { throw new IllegalArgumentException("Argument count (" + argumentCount + ") doesn't match expected count (" + handlers.length + ")"); } for (int p = 0; p < argumentCount; p++) { handlers[p].apply(requestBuilder, args[p]); } return requestBuilder.build();}
这个方法,提供OkHttp3发起的网络请求需要的Request对象。
4、再谈Retrofit类的create方法
大致介绍完Retrofit类和ServiceMethod后,接着看Retrofit的create方法,前面说了其最后三行是关键代码
ServiceMethod serviceMethod = loadServiceMethod(method);OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);return serviceMethod.callAdapter.adapt(okHttpCall);
其中第一行代码讲了,是实例化ServiceMehod对象,第二行是实例化OkHttpCall对象,该OkHttpCall是Call接口的实现,最后调用了callAdapter.adapt方法。前面备注了要注意的就是这个adapt方法,不同的CallAdapter其对应的adapter方法不一样,如前面所说DefaultCallAdapterFactory 工厂类生产的CallAdapter adapt方法对应的返回参数是Call,而SimpleCallAdapter 对应adapt方法的返回参数是Observable,这就为之后RxJava结合Retrofit2使用留下了铺垫(解决疑惑3)。
我们看到当不添加.addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))方法时,默认的CallAdater adapt方法直接来什么参数返回什么,也就是返回OKHttpCall对象。
到这里应该知道在本文最开始在addCallAdapterFactory之后还使用了
Call<ZhuanLanAuthor> call = api.getAuthor("qinchao");
这种方式来返回Call在运行时,肯定是会报错的,应为实际上api.getAuthor方法返回的是Observable变量,这地方只是为了方便后面讲解,才那么写的。
5、call.enqueue发起网络请求
这里的call.enqueue放弃网络请求的时候,实际上是OKHttpCall对象发起的网络请求,看起enqueue的部分代码
synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; failure = creationFailure; if (call == null && failure == null) { try { call = rawCall = createRawCall(); } catch (Throwable t) { failure = creationFailure = t; } }}if (failure != null) { callback.onFailure(this, failure); return;}if (canceled) { call.cancel();}call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) throws IOException { Response<T> response; try { response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } callSuccess(response); }}
其中createRawCall中通过获取ServiceMethod对象toRequest方法生成call对象,儿toRequest方法实际上就是获取的我们传入的.client(new OkHttpClient()) OkHttpClient对象(解决疑惑1、疑惑2)。
private okhttp3.Call createRawCall() throws IOException { Request request = serviceMethod.toRequest(args); okhttp3.Call call = serviceMethod.callFactory.newCall(request); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call;}
然后通过call对象调用call.enqueue方法发起网络请求,并执行回调。
到这里对Retrofit2的源码分析就算完成了,在分析的过程中也算是解决了文章开始提出的四个疑问。
6、参考文献
1、Retrofit2 源码解析http://www.jianshu.com/p/c1a3a881a1442、OkHttp3的基本用法http://www.jianshu.com/p/1873287eed87
7、Demo地址
Android Demo:https://github.com/Yoryky/AndroidDemo.git
- Retrofit2实现源码分析
- Retrofit2.0源码分析
- Retrofit2源码分析
- Retrofit2 源码分析
- Retrofit2 源码分析
- Retrofit2.0源码分析
- Retrofit2 源码分析
- retrofit2源码分析
- Retrofit2源码分析
- retrofit2源码分析
- retrofit2.0源码分析
- Retrofit2源码分析
- Retrofit2 源码分析(清晰版)
- Retrofit2源码初探
- Retrofit2源码解读
- Retrofit2源码解析
- Retrofit2 源码解析
- Retrofit2.0源码解析
- 网易2017内推笔试2:统计回文 [python]
- java 第五课笔记
- 自定义mabatis generator
- JS中调android的方法
- JAVA后端总结
- Retrofit2实现源码分析
- JDK自带工具keytool生成ssl证书
- 给一个url获得后台的数据
- 分词工具实验(代码示例)
- Qt 控件添加阴影效果
- 检测接口加密类
- 外部表与管理表
- 汉诺塔递归实现与栈实现
- 网络基础-字节序