Retrofit源码解析
来源:互联网 发布:道路横断面效果图软件 编辑:程序博客网 时间:2024/06/18 00:04
借鉴的
别人写的源码解析
比较详细的retrofit2源码解读
首先Retrofit的使用:
1、创建出Retrofit对应实例
2、构建API对应的Interface实例
3、通过api调用对应方法获取返回
4、call.enqueue()加入队列转入主线程
retrofit的使用
GET方式@Query 以及@Querymap
@GET("/appServer/interface/commonconf/checkVersion")// Call<Version> getVersion(@Query("appId")String apid,@Query("curVersion")String version);//query要求("这之中的形参与服务端对应") Call<Version> getVersion(@QueryMap Map<String,String> params);//querymap要求map中put进去的key与形参对应@Post方式
@FormUrlEncoded与@Multipart两者其中FormUrlEncoded对应Field以及FieldMap而Multipart对应part以及partMap功能大致相同只是Multpart可以用来上传文件
@Field以及@FieldMap与@query相同
@Part @PartMap 与Field@FieldMap相同但可以使用流做文件上传
b. @Body
- 作用:以
Post
方式 传递 自定义数据类型 给服务器 - 特别注意:如果提交的是一个Map,那么作用相当于
@Field
不过Map要经过
FormBody.Builder
类处理成为符合 Okhttp 格式的表单,如:
Retrofit的原理
retrofit.create(ZhuanLan.class)对应的使用动态代理的方案,实现了解耦
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, @Nullable 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<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }调用invoke后调用loadServiceMethod方法
ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder<>(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
Retrofit中请求交友okhttp执行;通过动态代理解析出interface中的参数、路径等这个在ServiceMethod中进行 等等
private void parseMethodAnnotation(Annotation annotation) { if (annotation instanceof DELETE) { parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false); } else if (annotation instanceof GET) { parseHttpMethodAndPath("GET", ((GET) annotation).value(), false); } else if (annotation instanceof HEAD) { parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false); if (!Void.class.equals(responseType)) { throw methodError("HEAD method must use Void as response type."); } } else if (annotation instanceof PATCH) { parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true); } else if (annotation instanceof POST) { parseHttpMethodAndPath("POST", ((POST) annotation).value(), true); } else if (annotation instanceof PUT) { parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true); } else if (annotation instanceof OPTIONS) { parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false); } else if (annotation instanceof HTTP) { HTTP http = (HTTP) annotation; parseHttpMethodAndPath(http.method(), http.path(), http.hasBody()); } else if (annotation instanceof retrofit2.http.Headers) { String[] headersToParse = ((retrofit2.http.Headers) annotation).value(); if (headersToParse.length == 0) { throw methodError("@Headers annotation is empty."); } headers = parseHeaders(headersToParse); } else if (annotation instanceof Multipart) { if (isFormEncoded) { throw methodError("Only one encoding annotation is allowed."); } isMultipart = true; } else if (annotation instanceof FormUrlEncoded) { if (isMultipart) { throw methodError("Only one encoding annotation is allowed."); } isFormEncoded = true; } } private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) { if (this.httpMethod != null) { throw methodError("Only one HTTP method is allowed. Found: %s and %s.", this.httpMethod, httpMethod); } this.httpMethod = httpMethod; this.hasBody = hasBody; if (value.isEmpty()) { return; } // Get the relative URL path and existing query string, if present. int question = value.indexOf('?'); if (question != -1 && question < value.length() - 1) { // Ensure the query string does not have any named parameters. String queryParams = value.substring(question + 1); Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams); if (queryParamMatcher.find()) { throw methodError("URL query string \"%s\" must not have replace block. " + "For dynamic query parameters use @Query.", queryParams); } } this.relativeUrl = value; this.relativeUrlParamNames = parsePathParameters(value); } private Headers parseHeaders(String[] headers) { Headers.Builder builder = new Headers.Builder(); for (String header : headers) { int colon = header.indexOf(':'); if (colon == -1 || colon == 0 || colon == header.length() - 1) { throw methodError( "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header); } String headerName = header.substring(0, colon); String headerValue = header.substring(colon + 1).trim(); if ("Content-Type".equalsIgnoreCase(headerName)) { MediaType type = MediaType.parse(headerValue); if (type == null) { throw methodError("Malformed content type: %s", headerValue); } contentType = type; } else { builder.add(headerName, headerValue); } } return builder.build(); } private ParameterHandler<?> parseParameter( int p, Type parameterType, Annotation[] annotations) { ParameterHandler<?> result = null; for (Annotation annotation : annotations) { ParameterHandler<?> annotationAction = parseParameterAnnotation( p, parameterType, annotations, annotation); if (annotationAction == null) { continue; } if (result != null) { throw parameterError(p, "Multiple Retrofit annotations found, only one allowed."); } result = annotationAction; } if (result == null) { throw parameterError(p, "No Retrofit annotation found."); } return result; }
真正执行网络请求的是OkHttpCall的execute方法
@Override public Response<T> execute() throws IOException { 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()); }可以看到默认使调用的是okhttp的网络请求
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(); int code = rawResponse.code(); if (code < 200 || code >= 300) { try { // Buffer the entire body to avoid future I/O. ResponseBody bufferedBody = Utils.buffer(rawBody); return Response.error(bufferedBody, rawResponse); } finally { rawBody.close(); } } if (code == 204 || code == 205) { rawBody.close(); return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { 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; } }
Retrofit build()创建时相关的4是类
Call 默认okhtpClient,CallFactory 负责网络请求
CallAdapter 平台适配器 适配不同的平台的网络请求 Retrofit目前支持Android Rxjava 等
CallbackExecutor负责将请求结果返回到主线程上
Converter 负责将请求结果转化成对应的数据类型如JSON XML 等
Retrofit 接口
1、Callback<T>回调
void onReSponse(Response<T> response)
void onFailure()
2、Converter<F,T> 解析
3、Call
4、CallAdapter
注意ServiceMethod中获取到request 交友httpCall(这个和volley的httpstack一样)执行最后获取到请求结果交友CallAdaper 处理
/** 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(); } /** Builds a method return value from an HTTP response body. */ T toResponse(ResponseBody body) throws IOException { return responseConverter.convert(body); }
执行Http请求
之前讲到,
OkHttpCall
是实现了Call
接口的,并且是真正调用OkHttp3
发送Http请求的类。OkHttp3
发送一个Http请求需要一个Request
对象,而这个Request
对象就是从ServiceMethod
的toRequest
返回的总的来说,
OkHttpCall
就是调用ServiceMethod
获得一个可以执行的Request
对象,然后等到Http请求返回后,再将response body传入ServiceMethod
中,ServiceMethod
就可以调用Converter
接口将response body转成一个Java对象结合上面说的就可以看出,
ServiceMethod
中几乎保存了一个api请求所有需要的数据,OkHttpCall
需要从ServiceMethod
中获得一个Request
对象,然后得到response后,还需要传入ServiceMethod
用Converter
转换成Java对象
Rertofit线程转换
Retrofit创建过程当中platform
static class Android extends Platform { @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } }而在ExecutorCallAdapter当中的enqueue方法通过callbackExecutor回调调用
@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(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); } }); } }); }
Volley对比优势
- 缓存处理;
Volley
自己就提供了一套完整的缓存处理方案,默认使用文件存储到磁盘中,并且提供了TTL SOFTTTL
这么体贴入微的机制;一个Request
可能存在两个Response
,对于需要显示缓存,再显示网络数据的场景真是爽的不要不要的。而Retrofit
中并没有提供任何和缓存相关的方案。- 代码简单,可读性高。
Volley
的代码是写的如此的直接了当,让你看起代码来都不需要喝口茶,这样的好处是我们我们需要修改代码时不太容易引入bug....囧- 同一个请求如果同时都在发送,那么实际上只会有一个请求真正发出去, 其它的请求会等待这个结果回来,算小小优化吧。实际上这种场景不是很多哈,如果有,可能是你代码有问题...
- 请求发送的时候提供了优先级的概念,但是是只保证顺序出去,不保证顺序回来,然并卵。
- 支持不同的Http客户端实现,默认提供了
HttpClient
和HttpUrlConnection
的实现,而Retrofit
在2.0版本之后,锁死在OkHttp
上了。6.支持请求取消Retrofit
1.发送请求真简单,定义一个方法就可以了,这么简单的请求框架还有谁?
Volley
?2.较好的可扩展性,Volley
中每一个新建一个Request
时都需要指定一个父类,告知序列化数据的方式,而Retrofit
中只需要在配置时,指定各种转换器即可。CallAdapter
的存在,可以使你随意代理调用的Call
,不错不错。。。3.OkHttpClient
自带并发光环,而Volley
中的工作线程是自己维护的,那么就有可能存在线程由于异常退出之后,没有下一个工作线程补充的风险(线程池可以弥补这个缺陷),这在Retrofit
中不存在,因为即使有问题,这个锅也会甩给OkHttp
,嘿嘿4.支持请求取消再次说明的是,
Retrofit
没有对缓存提供任何额外支持,也就是说它只能通过HTTP
的Cache control
做文件存储,这样就会有一些问题:1.需要Server
通过Cache control
头部来控制缓存,需要修改后台代码2.有些地方比较适合使用数据库来存储,比如关系存储,此时,Retrofit
就无能为力了3.缓存不在我们的控制范围之内,而是完全通过OkHttp
来管理,多少有些不便,比如我们要删除某一个指定的缓存,或者更新某一个指定缓存,代码写起来很别扭(自己hack请求头里面的cache contrl
)而在我们项目的实际使用过程中,缓存是一个比较重要的角色,
Retrofit
对缓存的支持度不是很好,真是让人伤心。。。但是,我们还是觉得在使用中Retrofit
真心比较方便,容易上手,通过注解代码可读性和可维护性提升了N个档次,几乎没有样板代码(好吧,如果你觉得每个请求都需要定义一个方法,那这也算。。),所以最后的决定是选择Retrofit。有人说了,
Volley
中的两次响应和缓存用起来很happy怎么办?嗯,我们会修改Retrofit
,使它支持文件存储和ORM
存储,并将Volley
的缓存 网络两次响应回调移接过来,这个项目正在测试阶段,待我们项目做完小白鼠,上线稳定之后,我会把代码开源,大家敬请关注。
- 【Retrofit】Retrofit源码解析
- Retrofit源码解析
- Retrofit源码解析
- Retrofit源码解析
- Retrofit源码解析
- Retrofit源码解析
- Retrofit源码解析
- Android Retrofit源码解析
- Retrofit 源码解析
- Retrofit源码解析
- Retrofit源码解析:RxJavaCallAdapterFactory
- Retrofit源码解析---初始化
- Retrofit 源码解析
- Retrofit源码解析
- Retrofit源码解析
- Retrofit源码解析(一)
- Retrofit源码解析(二)
- Retrofit源码解析(三)
- Noip 2012 同余方程
- SQL Server 2008R2 或更高版本数据库向低版本降级方法
- HTTP Status 500
- linux 下使用tgz包安装JAVA
- 禁止按钮多次点击的方法
- Retrofit源码解析
- Spring中aop概念以及用法
- 【Java_SE】作业练习1105
- ThreadPool
- java引用与参数传递
- 餐饮界的黑科技 餐厅厨房小票打印机趣味玩法
- C#调用RDP,实现远程桌面共享及控制
- 对象的克隆——原型模式(一)
- 对于加密证书的理解