Retrofit
什么是Retrofit
基于 RESTful Api设计规范的 Http 网络请求框架的封装。网络请求本质上还是使用OkHttp完成,而Retrofit负责网络网络请求接口的封装。
使用步骤
- 创建 Retrofit 实例,使用单例模式
- 创建描述网络请求的接口(Interface)并使用 注解 描述并配置网络请求参数
- 创建网络请求接口实例 retrofit.create();
- 发送网络请求(Request) enqueue,交由OkHttp处理请求
- OkHttp得到服务端响应(Response)后,交由Retrofit解析并处理
- 通过callbackExecutor从子线程切换到UI线程并通过回调将数据与状态传递到前台
源码分析
1.创建Retrofit实例
使用 Builder模式 创建一个Retrofit实例
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient httpClient = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/") // 设置网络请求的URL地址
.addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
.client(httpClient)
.build();
2.定义接口以及请求方法
public interface ApiServicie
{
@POST("/"+ RequestParams.VERSION+"/api/***")
Call<ResponseBody> getCall(@Body RequestBody body);
}
3.创建网络请求接口实例
private Map<String, Object> mServicePool = new ConcurrentHashMap<>();
/**
* 获取指定类型的service,把service做缓存处理,避免每次都创建;
* 创建并获取网络请求接口
* @param clazz 网络请求接口的字节码
* @param <T> 得到被动态代理的接口实例
* @return
*/
public synchronized <T> T getService(Class<T> clazz) {
Object service = mServicePool.get(clazz.getName());
if (service == null) {
service = mRetrofit.create(clazz);
mServicePool.put(clazz.getName(), service);
}
return (T) service;
}
// 使用动态代理的方式去拦截网络请求接口定义的方法
public <T> T create(final Class<T> service) {
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 使用动态代理,返回Service对象。当调用service.xxx()时会执行invoke方法并返回网络请求的对象Call
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
// 根据缓存策略实现延伸加载ServiceMethod对象
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;
}
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);
}
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);
}
return new ServiceMethod<>(this);
}
4.执行网络请求
// 生成网络请求Call对象
// 执行getCall方法时,会被动态代理的InvocationHandler.invoke拦截
Call<ResponseBody> call = getService(ApiService.class).getCall(body);
// 执行异步网络请求
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.code() == 200) {
// 处理请求成功
} else {
// 处理请求失败
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
// 处理请求失败
}
});
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor; // 实现将子线程线程切换到UI线程
final Call<T> delegate; // 静态代理OkHttpCall
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "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);
}
});
}
});
}
}
OkHttpCall:
@Override public void enqueue(final Callback<T> callback) {
okhttp3.Call call
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
// 生成原生的请求对象,会把请求参数通过serviceMethod.toCall()交由ParameterHandler组成网络请求头
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
// 调用OkHttp的enqueue执行网络请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
// 将服务器传回来的数据进行解析,生成对应的接收类型。
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
// 将结果通过回调传递出去
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
private okhttp3.Call createRawCall() throws IOException {
// args :网络请求传递的参数
okhttp3.Call call = serviceMethod.toCall();
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
}
RealCall
public void enqueue(Callback responseCallback) {
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
Dispatcher
public final class Dispatcher {
private int maxRequests = 64; // 最多缓存 64 个请求
private int maxRequestsPerHost = 5; // 同一个host最多允许5个链接存活
private @Nullable ExecutorService executorService; // 使用线程池执行请求
// 请求连接池
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// 核心线程数为0,最大线程数为无限大,线程最多存活时间为1分钟。
// 当执行第二个线程时,第一个请求已经完成且在存活时间内,则复用第一个线程。
public synchronized ExcutorService excutorService() {
if(executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
}
// 执行异步网络请求
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
// 同步网络请求
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
}
public class AsyncCall extends NameRunnable{
@Override protected void execute() {
try {
// 使用责任链模式执行网络请求并得到结果
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
RealCall
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors()); //自定义的拦截器
interceptors.add(retryAndFollowUpInterceptor); //重试拦截器,请求失败后重试, 如果出现IO异常则直接取消
interceptors.add(new BridgeInterceptor(client.cookieJar())); //桥接拦截器,处理请求
interceptors.add(new CacheInterceptor(client.internalCache())); //缓存拦截器,处理请求缓存
interceptors.add(new ConnectInterceptor(client)); //连接拦截器,创建HTTP连接
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket)); //网络请求拦截器,开始网络请求
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
拦截器
将一个请求的过程分解,然后对每一个过程进行处理(打包),得到响应后在对数据进行解包.
- 重试拦截器 - RetryAndFollowUpInterceptor
public Response intercept(Chain chain) throws IOException {
//......
int followUpCount = 0; // 重试计数器
//通过一个循环来重新尝试请求
while (true) {
// 如果出现IO异常,则直接取消
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
// 1.执行下一个拦截器
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
}
// 2.检测服务端的响应 response, 是否需要重定向和以及客户端是否支持超时重连, 如果不支持则直接返回响应。
Request followUp = followUpRequest(response, streamAllocation.route);
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
//3. 返回response,请求完成
return response;
}
if (++followUpCount > MAX_FOLLOW_UPS) { // 最多尝试20次
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
//4.重新设置请求
request = followUp;
//.......
}
}
- 桥接拦截器 - BridgeInterceptor
public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
// 处理请求体
if (body != null) {
// ......
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
// 默认支持长连接
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
// 默认支持 gzip 压缩
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
// 默认使用cookie在用户端保存信息
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
// 默认支持代理
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
// 执行请求
// .....
}
return responseBuilder.build();
}
总结:桥接连接器主要是优化请求头的一些配置,例如:默认支持长连接;默认支持 gzip 压缩。
- 请求缓存拦截器 - CacheInterceptor
该拦截器主要是处理HTTP响应缓存的,如果。
总结如下:
- 使用 DiskLruCache 管理Http的响应缓存;
- 使用 CacheControll 验证缓存是否可用。
- 连接拦截器 - ConnectInterceptor
首先,OkHttp 会将请求缓存在一个连接池(ConnectionPool : 最多有5个空闲链接,一个链接最多存活5分钟,使用核心线程数为0,最大线程数为1,每个线程最多存活1分钟的线程池)中;接着,收到请求时,根据请求地址从连接池中查找是否有链接,如果有则返回;否则创建一个新的链接返回并加入连接池;
- CallServerInterceptor
该拦截器是整个请求的最后一步: 与服务端交换数据。
public Response intercept(Chain chain) throws IOException {
//......
//写入请求头数据
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
//......
if (responseBuilder == null) {
// Write the request body if the "Expect: 100-continue" expectation was met.
realChain.eventListener().requestBodyStart(realChain.call());
long contentLength = request.body().contentLength();
//这里写入请求体
CountingSink requestBodyOut =
new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
realChain.eventListener()
.requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
} else if (!connection.isMultiplexed()) {
streamAllocation.noNewStreams();
}
}
// 执行请求
httpCodec.finishRequest();
if (responseBuilder == null) {
//这里请求返回,读取响应请求头
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
// 根据响应创建 Response
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
realChain.eventListener()
.responseHeadersEnd(realChain.call(), response);
int code = response.code();
if (forWebSocket && code == 101) {
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
//读取返回内容
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
//......
return response;
}
总结
- Retrofit使用接口与注解描述一个HTTP请求;使用动态代理(反射技术)的方式创建接口实例,在调用接口方法时实现动态拦截。 参考上面第三步:创建网络请求接口实例
- 调用OkHttpCall执行网络请求与数据解析,由于 OkHttpCall是不带线程切换的,Retrofit 使用适配器 CallAdapter 包装 OkHttpCall, 并通过callbackExecutor将结果由子线程切换到UI线程;
- 使用ParameterHandler实现传递的参数向网络请求的转换;
- okhttp请求流程:首先通过调度器Dispatcher处理请求任务(请求又分为同步请求和异步请求),接着通过拦截器处理请求, 最后再举哀那个