Retrofit请求时序图:
1、Retrofit框架是什么
Retrofit是一个框架,它封装了网络请求功能,将网络请求的一整套流程都封装好了
- 用来解决什么问题?
- 使用OkHttp进行网络请求时,需要封装Request请求,发起请求,处理响应结果,如json格式数据转换,和线程切换
- 而使用Retrofit框架将上面的操作都封装好了,可直接拿来使用。
2、Retrofit的使用
2.1、添加依赖
java
com.squareup.retrofit2:retrofit:2.9.0
2.2、创建一个请求接口
-
该接口封装了所有需要发起的请求
-
解析:
- GitHubService是一个接口,发起请求时,会拿到该接口的实现类调用其方法(listRepos)
- 请求方法listRepos,通过注解设置了请求的参数(如method,url和入参),之前使用OkHttp时,需要创建一个Request对象实例,这里采用注解方式进行数据设置
less
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
2.3、创建Retrofit单例
- 通过baseUrl方法,设置请求的前缀,为何这样做呢?
- 因为每个应用请求时都是访问自己本公司的域名接口,且这个域名是唯一的,所以多个请求的url前缀都一样,为节省url前缀写法,统一在baseUrl方法中设置,至于每个接口的不同部分,则在每个请求接口中设置
- client方法可设置自定义的OkHttpClient对象实例,不调用的话内部有默认的对象创建 retrofit.create(GitHubService.class); 调用retrofit的create方法会创建请求接口GitHubService的实现类
ini
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.client(initOkHttpClient())
.build();
GitHubService service = retrofit.create(GitHubService.class);
2.4、发起请求,获取响应数据
- 调用设置的接口请求方法,获取响应数据
kotlin
Call<List<Repo>> reposCall = service.listRepos("octocat");
reposCall.enqueue(object : Callback<List<Repo>> {
override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
}
override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
}
})
3、流程解析
3.1、Retrofit对象创建
- 通过Builder构建者模式设置参数,最后调用build方法创建Retrofit对象实例
java
retrofit2.Retrofit.Builder
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private @Nullable HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// 创建默认的OkHttpClient对象
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 数据获取到后,线程切换回调处理器callbackExecutor(实现类是retrofit2.Platform.Android.MainThreadExecutor,内部也是通过Handler进行线程切换)
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 添加请求适配器到集合中 callAdapterFactories,默认值为(platform.defaultCallAdapterFactories(callbackExecutor))
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// 添加转换器到集合中 converterFactories
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
// 创建Retrofit对象实例
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
}
}
3.2、GitHubService接口实现类
- retrofit2.Retrofit#create
切面编程,动态代理
- 在Retrofit的create方法中,通过Proxy.newProxyInstance动态代理的方式创建GitHubService接口实现类
- 后面在使用该接口实现类调用方法时,会进入InvocationHandler的invoke方法,请求方法的名称和参数信息会在invoke方法的参数中传入
typescript
public <T> T create(final Class<T> service) {
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 {
// If the method is a method from Object then defer to normal invocation.
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);
}
});
}
3.3、发起请求
ini
Call<List<Repo>> repos = service.listRepos("octocat");
- 当调用GitHubService的listRepos方法时,最终会调用到创建动态代理对象InvocationHandler的invoke方法
- 接着调用loadServiceMethod(method).invoke(args);并返回数据
- loadServiceMethod:获取ServiceMethod对象
- retrofit2.Retrofit#loadServiceMethod
- 该方法中,会先去缓存中根据method为key值进行查找
- 缓存中没有调用ServiceMethod.parseAnnotations(this, method);创建一个ServiceMethod实例
- 最后将该实例对象保存到缓存serviceMethodCache中,这样下次再调用该请求方法时就不用另新创建ServiceMethod实例对象了
sql
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
retrofit2.ServiceMethod#parseAnnotations
- 通过RequestFactory.parseAnnotations()方法创建RequestFactory 对象
- 最终调用HttpServiceMethod.parseAnnotations()返回HttpServiceMethod继承类
java
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.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
3.4、HttpServiceMethod
核心类
- retrofit2.HttpServiceMethod#parseAnnotations
ini
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
// 获取请求方法上设置的所有注解,通过這些注解可以知道请求的method和请求url
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) { // 判断该请求方法是否是Kotlin类型的挂起函数(先不考虑)
...
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
// 获取请求方法返回的数据类型,当前返回类型是Call,如果和RxJava配合使用就会返回Observer等其他类型,需要通过converterFactorie类型转换处理
adapterType = method.getGenericReturnType();
}
// 获取合适的请求适配器 CallAdapter对象
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
// 获取请求方法的返回值类型
Type responseType = callAdapter.responseType();
...
// 根据返回类型获取响应数据转换器
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory; // callFactory 为OkHttpClient对象实例
// 非kotlin挂起函数,将参数requestFactory, callFactory, responseConverter, callAdapter封装为CallAdapted对象
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
... // 挂起函数处理逻辑
}
3.5、CallAdapted:
- parseAnnotations方法最终返回了HttpServiceMethod内部子类CallAdapted的实例
- 所以loadServiceMethod方法,最开始创建了CallAdapted对象实例并保存到缓存中,接着调用invoke方法,调用的是retrofit2.HttpServiceMethod#invoke
- invoke方法中封装了OkHttpCall请求类,该类的作用域OkHttp框架中的RealCall类型,其中也实现了同步请求
- 异步请求的方法
- 继续调用adapter方法,会调用子类CallAdapted的adapt方法
less
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
retrofit2.HttpServiceMethod.CallAdapted#CallAdapted
- adapt方法中,真实调用的类是,Retrofit中设置的请求适配器callAdapter对象
scala
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);
}
}
3.6、callAdapter的真实实现类为:DefaultCallAdapterFactory
- 获取callAdapter的方法是:retrofit2.HttpServiceMethod#createCallAdapter
- 最终会调用retrofit2.Retrofit#callAdapter
kotlin
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
/**
* 从集合callAdapterFactories最后一个元素开始获取设置的CallAdapter实现类,返回的值不为空,即为所求
*/
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;
}
}
- 那保存的地方又在哪里呢?
- 在Retrofit的build构建函数中设置:retrofit2.Retrofit.Builder#build
- 在platform.defaultCallAdapterFactories方法中,(hasJava8Types为true)会将CompletableFutureCallAdapterFactory和DefaultCallAdapterFactory组成集合返回
- 且DefaultCallAdapterFactory是集合尾部加入,所以在获取的时候也是先拿到DefaultCallAdapterFactory对象判断
less
public Retrofit build() {
..
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
}
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
retrofit2.DefaultCallAdapterFactory
- 其中get方法,就是HttpServiceMethod.parseAnnotations每次在解析方法注解时调用createCallAdapter方法获取CallAdapter对象最终的实现
3.7、ExecutorCallbackCall
-get方法返回的是CallAdapter接口的匿名实现类,其中adapter方法最终返回的ExecutorCallbackCall<>(executor, call)
- 其中executor对象是Retrofit构造函数时,传入的MainThreadExecutor对象,用于进行线程切换
- 则最终调用listRepos方法返回的Call结果是ExecutorCallbackCall实现类
- 继续调用enqueue方法,会交给delegate进行实现,也就是OkHttpCall
- 且OkHttpCall的请求结果回调,会交给 callbackExecutor.execute进行线程切换处理到主线程
java
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 判断请求方法返回类型是否是Call,非Call类型返回null,这样的话就会继续从CompletableFutureCallAdapterFactory进行查看
if (getRawType(returnType) != Call.class) {
return null;
}
...
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
@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()) {
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));
}
});
}
}
OkHttpCall.enqueue发起请求,获取response响应并完成数据解析
- retrofit2.OkHttpCall#enqueue
java
final class OkHttpCall<T> implements Call<T> {
...
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
...
// call对象是OkHttpClient调用newCall方法获取到的RealCall实现类
call = rawCall = createRawCall();
// 接下来就是OkHttp框架发起请求的流程了
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) {
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
}
}
});
}
}
4、响应数据解析
- retrofit2.OkHttpCall#parseResponse
- 先判断响应码,响应码在小于200,或大于等于300时,说明请求出错
- 最后调用响应转换器的convert方法进行数据解析转换,我们最终的目的是将返回的数据流解析为Bean封装对象
scss
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 {
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;
}
}
4.1、Gson数据解析
- retrofit2.converter.gson.GsonResponseBodyConverter#convert
- 最后通过调用google的Gson库对象响应数据进行解析
java
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
}
- 未完待续
- Retrofit框架中使用到的设计模式
- 与RxJava配合使用