Retrofit的使用
从一道面试题开始说起 枚举、动态代理的原理
首先,先要拿到一个Retrofit的实例:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.build();
然后需要一个接口:
interface LoginService {
@GET("user/test") Call isLogin();
}
然后通过Retrofit的实例创建这个接口的实例:
LoginService loginService = retrofit.create(LoginService.class);
拿到这个实例就能够进行网络请求了。
loginService.isLogin().enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
}
});
create方法
public <T> T create(final Class<T> service) {
//判断传入的class是否能够被代理
validateServiceInterface(service);
//动态代理
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
//平台
private final Platform platform = Platform.get();
//空参
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//如果该方法是来自 Object 的方法,则推迟到正常调用。
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
//根据平台来确定返回值
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
从上面的源码中可以看出,create方法使用了动态代理,来返回一个接口的实例。动态代理上面有一篇博客。
loadServiceMethod方法
然后再来看一下loadServiceMethod这个方法返回了什么吧。
ServiceMethod<?> loadServiceMethod(Method method) {
//有缓存的话会从缓存中拿到result,然后返回,网络请求的话这肯定为空
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//在这拿到result
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
从上面的源码中可以看出来,应该调用了ServiceMethod这个类的parseAnnotations方法。然后来看一下这个类:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
//在这又调用了HttpServiceMethod的parseAnnotations方法
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
//没有重写invoke方法
abstract @Nullable T invoke(Object[] args);
}
HttpServiceMethod的parseAnnotations方法:
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//判断是否是协程
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
//在这创建了CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(
method,
"'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
//在这创建了ResponseConverter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
//不是协程就返回CallAdapted这个类
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
//使用协程返回这个类
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
在这个类中有invoke方法,所以在上面的create方法中调用的invoke方法就是这个类中的invoke方法,返回的具体类就是CallAdapted这个类,先看一下这个invoke方法:
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
再来看一下这个CallAdapted这个类:
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
OkHttpCall
在invoke方法中创建了一个OkHttpCall,然后来看一下这个类,这个类中有一个enqueue方法:
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
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) {
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,这里面调用了转换器,在这将原始的数据进行解析
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@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) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
在这里就能够看到retrofit是封装了okhttp,它的内部是使用OkHttp来进行网络请求的。
parseResponse方法:
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);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//这就是需要转换器来进行重写的,转换器需要实现这个方法
T body = responseConverter.convert(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;
}
}
这是OkHttpCall这个类的主要方法,然后返回去看adapt方法,当在invoke方法中调用了adapt方法,就需要来找到其实现方法,在CallAdapted这个类中的adapt方法:
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
在这调用了callAdapter的adapt类,所以就需要找到这个callAdapter的具体类。
CallAdapter
向上找就能够找到这个callAdapter来自Retrofit这个类,一直找就会发现,在nextCallAdapter这个方法中就会返回adapter:
public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
StringBuilder builder =
new StringBuilder("Could not locate call adapter for ").append(returnType).append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
这个类中就会发现,其实就是将callAdapterFactories这个集合遍历了一遍,然后找到合适的adapter
进行返回。现在就需要找到callAdapterFactories中存在哪些callAdapter。
在Retrrofit的Builder类中的build方法中给callAdapterFactories了一个默认值
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//添加了一个默认值
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
这个默认值是DefaultCallAdapterFactory,callbackExecutor是Android这个类中的默认值,返回了一个MainThreadExecutor。
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
DefaultCallAdapterFactory中重写了adapt方法:
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
这个adapt方法返回了ExecutorCallbackCall这个类,所以从这里能够看出在使用的时候调用的enqueue方法其实就是ExecutorCallbackCall这个类中的enqueue。然后来看一下这个类中的enqueue方法:
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
其中delegate为之前所说的OkHttpCall这个类,在这调用了OkHttpCall中的enqueue方法,然后在这调用了callbackExecutor.execute,这个callbackExecutor其实就是那个MainThreadExecutor类:
Java static final class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.*getMainLooper*()); @Override public void execute(Runnable r) { handler.post(r); } }
在这使用handler来进行切换线程,切换到了主线程,然后在主线程中进行回调。在这,Retrofit调用的全部流程就能够走一遍了。所以最终调用的enqueue其实是ExecutorCallbackCall中的enqueue。
Converter
转换器的流程和callAdapter的流程基本一样,都是HttpServiceMethod中的parseAnnotations这个方法中调用create···方法,然后就会到Retrofit中去执行next···方法,然后在OkhttpCall拿到数据之后去将数据进行转换。添加也适合CallAdapter一样的,都是在Retrofit的Builder类中进行添加。