Retrofit2 源码分析
2016-07-22 16:54
399 查看
什么是Retrofit
A type-safe HTTP client for Android and Java一款在Java和Android平台上使用的类型安全的Http客户端
Retrofit的特点
将API请求转化为接口,具体的接口方法代替各个API使用注解标记请求方法类型、参数类型
支持Multipart和文件上传
将返回结果转化为对象,并可自定义数据转化器
提供异步请求方式
可自定义网络客户端okHttpClient、HttpClient
关键步骤
请求解析请求封装
请求异步处理
请求结果转换
源码分析
关键代码: T create(final Class service) 这个方法包含了上述流程中的请求解析和封装。public <T> T create(final Class<T> service) { //检查接口类的合法性:1、必须是接口类型。2、不能继承其他接口。 Utils.validateServiceInterface(service); if (validateEagerly) { //如果需要提前验证接口方法,则走此逻辑。 //遍历接口中的方法Method,并包装成ServiceMethod,缓存到LinkedHashMap中 eagerlyValidateMethods(service); } //使用Java动态代理生成接口具体对象。并封装成ServiceMethod--->OkHttpCall 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); } //上面部分可以忽略,如果是Object或平台自带的方法,不进行代理。 //如果是我们在接口中声明的方法,则构造一个ServiceMethod对象,相当于请求解析。然后根据ServiceMethod和参数构造一个OkHttpCall,相当于请求封装。 //最后一句,serviceMethod.callAdapter就是Retrofit里面指定的CallAdapter。CallAdapter的作用是将一个请求转化成AdapterFactory要求的返回类型。 //如果没有自定义返回类型,Retrofit会使用默认的ExecutorCallAdapterFactory //Retrofit2执行接口请求时会返回一个Call<T>对象,当调用Call<T>的enqueue或execute方法时,才会真正去请求。 ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }
1.请求解析
Retrofit的请求解析是通过ServiceMethod这个类完成,将一个接口方法转换成一个HTTP请求。具体的解析过程很繁杂,但是很简单。无非就是取到接口方法的各类注解,然后分别
解析请求类型(parseMethodAnnotation(Annotation anotattion))
解析参数(parseParameter(int p, Type parameterType, Annotation[] annotations))
创建CallAdapter (retrofit.callAdapter(returnType, annotations))
创建ResponseConverter(retrofit.responseBodyConverter(responseType, annotations))
解析完成后,调用ServiceMethod的构造方法new ServiceMethod<>(this);
构造方法如下
ServiceMethod类的构造也是通过Builder模式实现的,下面一一介绍一下ServiceMethod中全局变量的含义。 ServiceMethod(Builder<T> builder) { //Http请求创建工厂,在创建Retrofit对象时指定,类型为okhttp3.Call.Factory,默认的是OkHttpClient this.callFactory = builder.retrofit.callFactory(); //请求适配器,将请求结果转换成指定类型Call<T> this.callAdapter = builder.callAdapter; //网络请求基础域名地址,可在创建Retrofit对象时指定,也可以通过@URL注解指定 this.baseUrl = builder.retrofit.baseUrl(); //请求结果转化器 this.responseConverter = builder.responseConverter; //Http请求类型 String类型,如“GET”/“POST” this.httpMethod = builder.httpMethod; //接口相对地址 this.relativeUrl = builder.relativeUrl; //请求头信息 Retrofit支持为某个接口单独设置请求头 this.headers = builder.headers; //内容类型即请求头中设置Content-Type的值 this.contentType = builder.contentType; //是否包含请求体,Post和Put请求是由请求体的 this.hasBody = builder.hasBody; //是否使用表单编码格式,当存在@FormUrlEncoded注解,此字段为true this.isFormEncoded = builder.isFormEncoded; //是否是多部件上传,当存在@MuitlPart注解时,此字段为true this.isMultipart = builder.isMultipart; //参数注解列表,即由注解指定的参数名称列表。如@Filed("id") this.parameterHandlers = builder.parameterHandlers; }
除了构造方法,还有两个比较重要的方法 toRequest(Object … args)和toResponse(ResponseBody body)。他们分别使用当前ServiceMethod存储的请求方法信息,生成一个真正的Http请求和自定义解析后的响应。
请求封装
/** 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); }
请求异步、同步处理
Retrofit2中同步、异步请求是由okHttp3.Call实现的。
异步请求
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); } @Override public void onFailure(okhttp3.Call call, IOException e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callSuccess(Response<T> response) { try { //请求成功后,通过回调CallBack将结果回传给调用者 callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } });
同步请求
@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()); }
请求结果转换
当请求结束后,会调用parseResponse(okhttp3.Response rawResponse)方法
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) { return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { //此处将返回结果交由用户指定或Retrofit默认的Converter进行数据转换。默认的转换器有StreamingResponseBodyConverter、BufferingResponseBodyConverter、ToStringConverter等。 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; } }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories