我们从简单的使用开始
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
Retrofit 使用方法注解的方式把Java接口转化成HTTP请求
首先我们声明接口
public interface GitHubService {
//获取github上用户信息
@GET("users/{user}")
Call userInfo(@Path("user") String user);
}
Retrofit使用四部曲
- 构建一个Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
- 生成一个GitHubService接口的实现
GitHubService service = retrofit.create(GitHubService.class);
- 创建一个请求
Call call = service.userInfo("humanheima");
4.同步或者异步执行请求
4.1 同步请求
try {
Response response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
注意不要在主线程直接调用,不然会抛出android.os.NetworkOnMainThreadException
4.2 异步执行
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
ResponseBody body = response.body();
if (body != null) {
try {
Log.d(TAG, "onResponse: " + body.string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
}
});
1.构建一个Retrofit实例。
首先看一下Retrofit.Builder类的构造函数
public Builder() {
this(Platform.get());
}
Builder(Platform platform) {
this.platform = platform;
}
Retrofit.Builder类的构造函数内部初始化了一个Platform实例。Platform代表Retrofit的使用平台。我们在Android中使用Retrofit,平台就是Android。
static class Android extends Platform {
//默认的回调执行器
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
//看到了Handler。可以猜想,回调之所以是在主线程执行,还是使用handler来实现的
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
接下来看一下Retrofit.Builder类的build方法
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//注释1处,初始化callFactory
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//初始化回调执行器
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//注释2处,使用平台默认的回调执行器
callbackExecutor = platform.defaultCallbackExecutor();
}
//注释3处,防御性拷贝callAdapterFactories,并添加默认的CallAdapter.Factory
List callAdapterFactories = new ArrayList<>
(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//注释4处,防御性拷贝converters,并添加内置的converter factory
List converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
//首先添加内置的converter factory到converter factory list中
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//创建Retrofit实例
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
注释1处,创建了一个OkHttpClient对象。
注释2处,如果没有传入回调执行器,则使用平台默认的回调执行器,在Android平台中就是一个MainThreadExecutor
对象。
注释3处,添加了平台默认的CallAdapter.Factory。就是一个ExecutorCallAdapterFactory
对象,传入的是MainThreadExecutor
对象。
注释4处,首先添加了一个内置的Converter.Factory对象。是一个BuiltInConverters
对象。
最后Retrofit.Builder类的build()方法返回了一个Retrofit实例。
Retrofit的构造函数
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List converterFactories, List callAdapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;//是一个OkHttpClient对象
this.baseUrl = baseUrl;
this.converterFactories = converterFactories;
this.callAdapterFactories = callAdapterFactories;
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
2. 生成一个GitHubService接口的实现
GitHubService service = retrofit.create(GitHubService.class);
Retrofit的create 方法
public T create(final Class service) {
//1. 首先验证service是否合法
Utils.validateServiceInterface(service);
//2. 是否提前创建service里面的所有方法
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//3. 创建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, Object[] args)throws Throwable {
// service的所有方法调用,最终会转发到这里
// 如果是Object的方法,就正常调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//如果是default方法(Java8中的默认方法),Android中不用管,一定是false
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//3.1
ServiceMethod
create方法内部创建了我们传入的service接口的动态代理。就是说我们我们调用service中的任何方法,都会转发到这个动态代理的invoke方法中。
3. 创建一个请求
Call call = service.userInfo("humanheima");
这时方法就转发到service动态代理的invoke方法中了。
//3.1
ServiceMethod serviceMethod =(ServiceMethod) loadServiceMethod(method);
//3.2
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//3.3
return serviceMethod.callAdapter.adapt(okHttpCall);
3.1构建一个ServiceMethod实例,ServiceMethod把对接口方法的调用转为一个HTTP调用
//缓存ServiceMethod实例
private final Map> serviceMethodCache = new
ConcurrentHashMap<>();
Retrofit的loadServiceMethod方法
ServiceMethod, ?> loadServiceMethod(Method method) {
ServiceMethod, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//注释1处
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
首先在缓存中查找method对应的ServiceMethod,如果缓存中存在就直接返回,否则创建一个ServiceMethod并加入缓存。每个ServiceMethod只会创建一次。
接下来看一下ServiceMethod.Builder这个类。ServiceMethod.Builder负责检查接口方法上的注解,来构造一个可重复使用的服务方法。这个过程需要用到代价非常昂贵的反射操作,所以最好是只构建一个方法一次,然后重复使用它。Builder的实例不能被重用。
ServiceMethod.Builder的构造函数
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
ServiceMethod.Builder的build方法简化版
public ServiceMethod build() {
//1. 创建callAdapter
callAdapter = createCallAdapter();
//在这个例子中responseType就是ResponseBody
responseType = callAdapter.responseType();
...
//2. 创建responseConverter
responseConverter = createResponseConverter();
//3. 处理方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
//4. 创建parameterHandlers
parameterHandlers = new ParameterHandler>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
...
//5. 返回一个ServiceMethod实例
return new ServiceMethod<>(this);
}
- 创建callAdapter。CallAdapter对象把一个类型参数为R的
retrofit2.Call
转化成T类型的对象(Call转化成T)。CallAdapter的实例由构建Retrofit时候通过{Retrofit.Builder#addCallAdapterFactory(Factory)}方法设置的{CallAdapter.Factory}创建。
ServiceMethod.Builder类的createCallAdapter方法简化版
private CallAdapter createCallAdapter() {
//获取方法返回类型,在这个例子中,返回类型是Call
Type returnType = method.getGenericReturnType();
...
//获取方法注解
Annotation[] annotations = method.getAnnotations();
try {
//注释1处,根据方法的返回类型和方法注解返回CallAdapter
return (CallAdapter) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) {
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
注释1处,根据方法的返回类型和方法注解返回CallAdapter。
Retrofit的callAdapter方法
public CallAdapter, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
Retrofit的nextCallAdapter方法简化版
public CallAdapter, ?> nextCallAdapter(CallAdapter.Factory skipPast,
Type returnType, Annotation[] annotations) {
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
//注释1处,遍历callAdapterFactories,返回合适的CallAdapter
CallAdapter, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
}
Retrofit的callAdapter()方法内部会去遍历callAdapterFactories这个list,根据方法返回类型和注解,返回合适的callAdapter。
在上面的分析中,当我们构建一个默认的Retrofit实例的时候,在Retrofit.Builder的build()方法内部默认添加了一个平台相关的CallAdapter.Factory而Android平台相关的默认的CallAdapter.Factory就是一个ExecutorCallAdapterFactory对象。ExecutorCallAdapterFactory这个类暂且不去管他。默认情况下ServiceMethod 的callAdapter就是ExecutorCallAdapterFactory的get方法返回的对象。
- 创建Converter
responseConverter。负责把 okhttp3.ResponseBody
转化为T类型的对象。
private Converter createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
//注释1处,根据方法的返回类型和注解返回Converter
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) {
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
可见responseConverter也是由Retrofit提供的。
public Converter responseBodyConverter(Type type,
Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public Converter nextResponseBodyConverter(
Converter.Factory skipPast, Type type, Annotation[] annotations) {
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
//注释1处,遍历converterFactories,找到合适的converter
Converter converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter) converter;
}
}
}
Retrofit的responseBodyConverter()方法内部会去遍历converterFactories这个list,根据方法返回类型和注解,返回合适的responseConverter。
在上面的分析中,当我们构建一个默认的Retrofit实例的时候,在Retrofit.Builder的build()方法内部传入了一个内置的BuiltInConverters对象。BuiltInConverters这个类暂且不去管它。现在为ServiceMethod找到了responseConverter。
parseMethodAnnotation:负责解析检查方法注解,暂且略过。
创建parameterHandlers,内部会创建Converter,负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数;这个过程暂且不去看。
每个参数都会有一个 ParameterHandler,由 ServiceMethod的parseParameter 方法负责创建,其主要工作就是解析每个参数使用的注解类型(诸如 Path,Query,Field 等),对每种类型进行单独的处理。API 方法中除
@Body
,@PartMap
和@Part
类型的参数,都利用 Converter.Factory.stringConverter 进行转换。而@Body
,@PartMap
和@Part
类型的参数则利用 Converter.Factory.requestBodyConverter 进行转换。
现在ServiceMethod.Builder的build()方法可以返回一个实例了。
public ServiceMethod build() {
//5. 返回一个ServiceMethod实例
return new ServiceMethod<>(this);
}
ServiceMethod的构造函数
ServiceMethod(Builder builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
3.2是创建一个OkHttpCall实例
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
3.3 返回结果
return serviceMethod.callAdapter.adapt(okHttpCall);
ServiceMethod的adapt方法
T adapt(Call call) {
return callAdapter.adapt(call);
}
默认情况下,ServiceMethod的callAdapter就是ExecutorCallAdapterFactory的get方法返回的对象。
ExecutorCallAdapterFactory的get方法
@Override
public CallAdapter, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
//返回一个CallAdapter实例。
return new CallAdapter>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call adapt(Call call) {
//注释1处,返回ExecutorCallbackCall实例
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
ExecutorCallAdapterFactory的get方法创建了一个CallAdapter的匿名对象。该对象的
adapt方法返回了一个ExecutorCallbackCall对象。
注意,到这里Call
方法最终返回的是一个ExecutorCallbackCall
对象。ExecutorCallbackCall类是ExecutorCallAdapterFactory的静态内部类,实现了retrofit2.Call接口。
ExecutorCallbackCall的构造函数
static final class ExecutorCallbackCall implements Call {
final Executor callbackExecutor;//回调执行器
final Call delegate;//一个OkHttpCall对象
ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
注意一下,在Android平台下,我们传入的回调执行器是一个MainThreadExecutor对象,用来将执行结果post到主线程,我们下面分析。
4. 现在到了Retrofit使用四部曲的第四步,执行请求。
4.1 同步请求execute
ExecutorCallbackCall的execute方法就是调用了代理对象的execute方法。
@Override
public Response execute() throws IOException {
return delegate.execute();
}
OkHttpCall的execute方法
@Override
public Response execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
//1. 一个请求只能被执行一次
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
//...
call = rawCall;
if (call == null) {
try {
//2. 创建一个okhttp3.Call
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//3. 转换okhttp3.Call的执行返回的响应
return parseResponse(call.execute());
}
- 一个请求只能被执行一次。
- 调用createRawCall方法,创建一个okhttp3.Call
OkHttpCall的createRawCall方法
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
createRawCall方法返回的是一个okhttp3.RealCall的实例。
- 转换okhttp3.Call的执行返回的响应
retrofit2.Response
。
Response parseResponse(okhttp3.Response rawResponse) throws IOException {
//临时保存原始响应体
ResponseBody rawBody = rawResponse.body();
//移除响应体的源(唯一有状态的对象),这样我们就可以传递响应。
//移除rawResponse的本来的响应体,传入一个没有内容的响应体
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
//...
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//注释1处,把原始响应体转化成我们希望的数据类型
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;
}
}
parseResponse方法首先会对响应做一些预处理,如果没有什么异常的话,就构建一个成功的响应返回。
在注释1处,在这个例子中,我们期望返回的数据类型就是okhttp3.ResponseBody
。
ServiceMethod的toResponse方法
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
内部调用了responseConverter的convert方法,在上面的分析中,我们知道默认情况下responseConverter就是BuiltInConverters的responseBodyConverter方法返回的对象。
final class BuiltInConverters extends Converter.Factory {
@Override
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
//我们的返回类型是ResponseBody
if (type == ResponseBody.class) {
//注释1处,我们只看没有使用Streaming注解的情况
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
}
在注释1处,我们只看没有使用Streaming注解的情况,返回的是一个BufferingResponseBodyConverter对象。
BufferingResponseBodyConverter类
static final class BufferingResponseBodyConverter implements Converter {
static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
try {
// 注释1处,缓存整个响应体避免将来出现IO异常
return Utils.buffer(value);
} finally {
value.close();
}
}
}
在注释1处,就是返回了整个响应体。
static ResponseBody buffer(final ResponseBody body) throws IOException {
Buffer buffer = new Buffer();
body.source().readAll(buffer);
return ResponseBody.create(body.contentType(), body.contentLength(), buffer);
}
最终执行的结果是返回了一个Response
对象。
4.2 异步请求execute
ExecutorCallbackCall内部的execute就是调用了代理对象的execute方法。执行完毕后会使用传入的callbackExecutor执行线程切换。
@Override
public void enqueue(final Callback callback) {
//调用代理的enqueue方法,并在执行完毕后使用回调执行器切换线程
delegate.enqueue(new Callback() {
@Override
public void onResponse(Call call, final Response response) {
//注释1处,执行成功,使用回调执行器切换线程
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
if (delegate.isCanceled()) {
//如果请求被取消了,抛出IOException
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override
public void onFailure(Call call, final Throwable t) {
//执行失败,切换线程
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
OkHttpCall的enqueue方法
@Override
public void enqueue(final Callback callback) {
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 {
//1.构建一个okhttp3.Call
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
//...
if (canceled) {
call.cancel();
}
//2. 使用okhttp3.Call的enqueue方法
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response response;
try {
//把okhttp3.Response转换成retrofit2的Response
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
//3. 成功的回调
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
//4. 失败的回调
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 response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
OkHttpCall的enqueue方法先判断请求是否执行过了。如果没有执行,就构建一个okhttp3.Call的实例,加入一个异步请求队列,执行成功或者失败后会调用传入的callback的对应方法。
如果执行成功,调用传入的callback的onResponse方法。
delegate.enqueue(new Callback() {
@Override
public void onResponse(Call call, final Response response) {
//注释1处,调用回调执行器execute的方法切换线程
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
if (delegate.isCanceled()) {
//如果请求被取消了,抛出IOException
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
//...
}
在注释1处,使用回调执行器切换线程。在Android中就是一个MainThreadExecutor对象。我们看一下MainThreadExecutor的execute方法。
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
内部就是通过handler来切换到了主线程。
listCall.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
//回到主线程执行
ResponseBody body = response.body();
if (body != null) {
try {
Log.d(TAG, "onResponse: " + body.string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
//回到主线程执行
}
});
至此:Retrofit使用四部曲就分析完了。
参考链接
- Retrofit
- Android Retrofit 2.0使用
- github
- 拆轮子系列:拆 Retrofit