Retrofit简要分析
Retrofit是对网络请求实现了一套请求架构封装,屏蔽底层网络实现,使网络请求像调用本地接口一样
基本使用例子
public interface GitHubService {//定义request方法以及返回需要的response类型
@GET("users/{user}/repos")
List<Repo> listRepos(@Path("user") String user);
@GET("users/{user}/repos")
Call<List<Repo>> listRepos2(@Path("user") String user,Callback<List<Repo>> calback);
} void usetest(){
static final String BASE_URL = "http://yourwebsite/services/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())//Response转换器,这里以GsonConvert为例
.addCallAdapterFactory(Java8CallAdapterFactory.create())//request处理Adapter
.build(); GitHubService service = retrofit.create(GitHubService.class);
// 直接调用
List<Repo> data = service.listRepos("user1"); // 异步callback方式
service.listRepos2("user2",new Callback<List<Repo>>() { @Override
public void onResponse(Call<List<Repo>> call,
Response<List<Repo>> response) {
data=response.body();
} @Override
public void onFailure(Call<List<Repo>> call, Throwable t) { Log.e("error",t.getMessage());
} });
}
调用流程
分析调用实现:首先从create开始
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);//校验service接口定义是否合法
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },//产生代理,实现对service接口调用
new InvocationHandler() {
private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
...
//每个接口最终转换为ServiceMethod,存储在serviceMethodCache中
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//网络访问与okhttp结合生成OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//发起请求,返回结果,解析返回
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
这里的OkHttpCall是Retrofit对自身Call接口实现,并不是okhttp3里的对象,通过实现接口内部封装okhttp3.Call,当然也可以替换其它网络库
看看call接口
public interface Call<T> extends Cloneable {
...
Response<T> execute() throws IOException;
...
void enqueue(Callback<T> callback);
...
boolean isExecuted();
...
void cancel(); /** The original HTTP request. */
Request request();
}
与okhttp里面call类似,只不过自身重新定义一下,降低耦合度
看看Okhttp3实现类
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;
private final Object[] args; private volatile boolean canceled; // All guarded by this.
private okhttp3.Call rawCall;
private Throwable creationFailure; // Either a RuntimeException or IOException.
private boolean executed; OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
......
@Override public void enqueue(final Callback<T> callback) {//异步请求
if (callback == null) throw new NullPointerException("callback == null"); okhttp3.Call call;
Throwable failure; synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
...
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);//解析response
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
} ......
});
} @Override public Response<T> execute() throws IOException {//同步调用请求
okhttp3.Call call; synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
......
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());//执行请求并解析
} 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;
} Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body(); // Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build(); ...... ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);//调用指定的Convert对response进行泛型转换
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;
}
}
convert最终调用来源Retrofit里的在builder里加入Converter.Factory
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null"); int start = converterFactories.indexOf(skipPast) + 1;
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;
}
} public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
看看GsonResponseBodyConverter实现
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 {//通过TypeAdapter转换为对应实体类型T
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
整理一下,Retrofit使用Jdk里的Proxy动态代理方式实现对接口方法调用,即当调用接口方法listRepos时,调用了Proxy中的invoke,将对应接口方法及注解封装为ServiceMethod对象,通过CallAdapter对OkHttpCall调用获取Response并将数据转换为T返回给调用者
Retrofit中build构建方法:
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
} okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {//检测网络请求client,如果没有指定则创建一个client
callFactory = new OkHttpClient();
} Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {//回调执行callback的线程,如果没有指定则采用默认主线程
callbackExecutor = platform.defaultCallbackExecutor();
} //CallAdapter指的是对request处理的CallAdapter,可以添加多个
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Converter是对response执行转换处理返回的T,可以添加多个
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories); return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
CallAdapter接口定义
public interface CallAdapter<R, T> {
//http 解析response 返回类型,不是咱接口定义泛型
Type responseType(); //处理response并转换为指定类型T
T adapt(Call<R> call); //CallAdapter 创建获取
abstract class Factory {
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*根据接口返回类型,注解类型判断当前CallAdapter是否支持,不支持返回为null
*/
public abstract CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit); /**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*获取指定index泛型参数上限,例如Map<String, ? extends Runnable> index为1参数上限为Runnable
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
} /**
* Extract the raw class type from {@code type}. For example, the type representing
* {@code List<? extends Runnable>} returns {@code List.class}.
*/
//获取解析类型class,例如List<? extends Runnable>,返回List.class
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
项目中有三种实现
RxJava Observable & Single - com.squareup.retrofit2:adapter-rxjava
Guava ListenableFuture - com.squareup.retrofit2:adapter-guava
Java 8 CompleteableFuture - com.squareup.retrofit2:adapter-java8
看一下java8实现
Java8CallAdapterFactory
private static final class BodyCallAdapter<R> implements CallAdapter<R, CompletableFuture<R>> {
private final Type responseType; BodyCallAdapter(Type responseType) {
this.responseType = responseType;
} @Override public Type responseType() {
return responseType;
} @Override public CompletableFuture<R> adapt(final Call<R> call) {
final CompletableFuture<R> future = new CompletableFuture<R>() {
@Override public boolean cancel(boolean mayInterruptIfRunning) {
if (mayInterruptIfRunning) {
call.cancel();
}
return super.cancel(mayInterruptIfRunning);
}
}; call.enqueue(new Callback<R>() {//调用okhttp Call方法异步调用
@Override public void onResponse(Call<R> call, Response<R> response) {
if (response.isSuccessful()) {
future.complete(response.body());
} else {
future.completeExceptionally(new HttpException(response));
}
} @Override public void onFailure(Call<R> call, Throwable t) {
future.completeExceptionally(t);
}
}); return future;
}
}
到这里我们已取到数据结果,再看看转换如何实现ServiceMethod的toResponse
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
通过serviceMethod 中的Converter<ResponseBody, R> responseConverter;实现进行解析
Converter为转换接口,实现类有以下
Gson - com.squareup.retrofit2:converter-gson
Jackson - com.squareup.retrofit2:converter-jackson
Moshi - com.squareup.retrofit2:converter-moshi
Protobuf - com.squareup.retrofit2:converter-protobuf
Wire - com.squareup.retrofit2:converter-wire
Simple Framework - com.squareup.retrofit2:converter-simpleframework
Scalars - com.squareup.retrofit2:converter-scalars
当然也可以自定义实现Converter,定制出符合自己需求转换器
从上面分析看出Retorfit中的3个核心部分:
1,Proxy 代理实现接口调用
2,CallAdapters request网络t处理
3,Converters response解析转换对应泛型T返回数据结果
Retrofit简要分析的更多相关文章
- Activity源码简要分析总结
Activity源码简要分析总结 摘自参考书籍,只列一下结论: 1. Activity的顶层View是DecorView,而我们在onCreate()方法中通过setContentView()设置的V ...
- Google发布SSLv3漏洞简要分析报告
今天上午,Google发布了一份关于SSLv3漏洞的简要分析报告.根据Google的说法,该漏洞贯穿于所有的SSLv3版本中,利用该漏洞,黑客可以通过中间人攻击等类似的方式(只要劫持到的数据加密两端均 ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(34)-文章发布系统①-简要分析
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(34)-文章发布系统①-简要分析 系列目录 最新比较闲,为了学习下Android的开发构建ASP.NET ...
- CVE-2015-5122 简要分析(2016.4)
CVE-2015-5122 简要分析 背景 最近在学习Flash漏洞的分析,其与IE漏洞的分析还是有诸多的不同(不便)之处,折腾了一阵子终于克服了没有符号表.Flash的超时定时器等问题.所以找到了去 ...
- Java7中的ForkJoin并发框架初探(中)——JDK中实现简要分析
原文发表于 2013 年 8 月 28 日 由 三石 根据前文描述的Doug Lea的理论基础,在JDK1.7中已经给出了Fork Join的实现.在Java SE 7的API中,多了ForkJoin ...
- [转]Java7中的ForkJoin并发框架初探(中)——JDK中实现简要分析
详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp85 根据前文描述的Doug Lea的理论基础,在JDK1.7中已经给 ...
- ITS简要分析流程(using Qiime)
Qiime安装 参考资料:http://blog.sina.com.cn/s/blog_83f77c940101h2rp.html Qiime script官方说明http://qiime.org/s ...
- Android初级教程通过简要分析“土司”源码,来自实现定义土司理论探讨
由于系统自带的土司瞬间即逝,而且非常难看.因此我们就希望自定义自己的土司风格.有些实例就是基于自定义土司完成的,例如金山卫士的火箭发射,基本原理就是个土司.但是在做出自己的土司风格之前,还是要简要分析 ...
- Android Hal层简要分析
Android Hal层简要分析 Android Hal层(即 Hardware Abstraction Layer)是Google开发的Android系统里上层应用对底层硬件操作屏蔽的一个软件层次, ...
- [Java] LinkedHashMap 源码简要分析
特点 * 各个元素不仅仅按照HashMap的结构存储,而且每个元素包含了before/after指针,通过一个头元素header,形成一个双向循环链表.使用循环链表,保存了元素插入的顺序. * 可设置 ...
随机推荐
- 《用Python写网络爬虫》pdf高清版免费下载
<用Python写网络爬虫>pdf高清版免费下载地址: 提取码:clba 内容简介 · · · · · · 作为一种便捷地收集网上信息并从中抽取出可用信息的方式,网络爬虫技术变得越来越有 ...
- 安卓虚拟键盘挡住input框解决办法
问题描述:ios弹出虚拟键盘的时候会自动将页面顶上去,不会遮住input输入框,而安卓则会挡住. 解决办法: 1.使用如下代码来区分安卓,存入localStorage中 if ((navigator. ...
- Java面向对象之回顾方法及加深
回顾方法及加深 方法的定义 修饰符 返回类型 break和return的区别 1.break:跳出switch,结束循环 2.return:代表方法结束,返回一个结果 方法名:注意规范.见名知意 参数 ...
- 在windows服务中托管asp.net.core
参考:https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-3.1& ...
- uniapp使用百度地图
要使用第三方百度地图,首先要去百度地图官方申请一个密钥,之后引入百度地图的API文件,参考使用文档即可开发使用.而在uniapp中是没法直接引入百度地图API文件的,我们要结合uniapp中的web- ...
- ps 合并两张图片为一张
打开PS并点击左上角的"文件":之后再点击"打开"(也可以按下快捷键"Ctrl+O"),打开文件选择窗口. 2 在打开的文件选择窗口中,找到 ...
- jekins+svn
1.jekins安装可以看jekins+shell随笔. 2.安装svn. yum -y install subversion 3.配置相关文件 mkdir 家目录 cd 到家目录修改conf下三 ...
- QT--QMainWindow窗口的状态栏设置
QMainWindow窗口状态栏 实时显示时间: 1.获取实时时间使用定时器QTimer, QTimer *timer = new QTimer(); connect(timer, &QTim ...
- Codeforces Global Round 17
Codeforces Global Round 17 A. Anti Light's Cell Guessing 坑点:\(n=1,m=1\) 时答案为 \(0\) . 其他情况:当 \(n=1\) ...
- Windows流媒体怎么关闭。
点击白色框,搜索服务. 步骤阅读 步骤阅读 2 选本地服务旁打开,然后下拉服务. 步骤阅读 步骤阅读 3 选择media,然后右键它属性. 步骤阅读 步骤阅读 4 然后点击停止,点击手动. 步骤阅读 ...