Retrofit简单使用
下面的是官网的例子:
//1、首先配置出一个retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
//2、定义一个网络请求的接口
public interface GitHubService {
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
//3、创建出一个service
GitHubService service = retrofit.create(GitHubService.class);
//4、通过service获取call
Call> repos = service.listRepos("octocat");
//5、执行call
repos.excute();
repos.enqueue();
在这个例子中所介绍到的基本就是retrofit的用法了,是不是觉得特别的简单呢,但是我们现在不仅仅只是要会用而已,而是要了解其内部实现的原理。我们按照我们的调用顺序来阅读源码。
Retrofit源码流程分析
retrofit内部元素
我们通过retrofit提供的Builder方法来创建实例。
Builder(Retrofit retrofit) {
platform = Platform.get();
callFactory = retrofit.callFactory;
baseUrl = retrofit.baseUrl;
converterFactories.addAll(retrofit.converterFactories);
adapterFactories.addAll(retrofit.adapterFactories);
// Remove the default, platform-aware call adapter added by build().
adapterFactories.remove(adapterFactories.size() - 1);
callbackExecutor = retrofit.callbackExecutor;
validateEagerly = retrofit.validateEagerly;
}
对于里面的每一个成员,都是非常重要的,我们下面来一一介绍。
plateform
因为retrofit支持多个平台,所以需要找到当前支持的平台,
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
在Android里面,return便是Android平台。
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
}
支持的Anroid平台带有一个默认的CallAdapter和CallBackExecutor,其中callbackAdapter是用来处理网络返回的response,将response包装成call,CallBackExecutor主要是用来callBack返回时做线程切换的。
callFactory
这个callFactory主要时用来封装网络请求成call的,需要将request生成一个Call。默认的OkhttpClient就是一个callFactory。
interface Factory {
Call newCall(Request request);
}
converterFactories
这个是解析网络返回值的工厂列表。通常添加Gson
adapterFactories
这个是用来处理网络返回response的工厂列表,默认包装成Call,也可以通过添加RxJava2CallAdapterFactory,将response包装成Observeable
callbackExecutor
这个网络回调的Executor,默认使用MainThreadExecutor,将callback回调在主线程执行。
ServiceMethod构建
serviceMethod对retrofit的service接口的每一个方法的转化,将请求地址,请求参数转化为对象,也就是retrofit执行单位的基本类型,这个类非常重要。我们来看看这个类的创建过程
new ServiceMethod.Builder(this, method).build();
=============>
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
通过上面的builder,我们可以发现在serviceMethod里面里面的成员,包括了retrofit,method,注解,参数类型,参数类型的注解数组。
- retrofit:表示serviceMethod所在的retrofit实例中
- method:接口方法
- methodAnotations:表示为这个方法上的注解
- parameterTypes:参数类型的数组
- parameterAnnotationsArrary:方法参数也有可能携带注解,表示注解实际取到的值的数组。
下面来看看实际的build方法创建:
public ServiceMethod build() {
//step1:
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
//step2:
responseConverter = createResponseConverter();
//step3:
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//获取出注解参数长度,并创建出parameterHandler,这个类是用来处理注解对应参数的。
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);
}
- step1:通返回类型和注解创建callAdapter,这个callAdapter是用来和OkHttpCall进行交互的。
private CallAdapter> createCallAdapter() {
//获取该方法的返回类型
Type returnType = method.getGenericReturnType();
//判断是否能够处理该类型。
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
//返回类型不能为空
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
//获取注解数组
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
我们来看看默认的callAdapter工厂:
@Override
public CallAdapter> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call adapt(Call call) {
return call;
}
};
}
- step2:通过返回类型和注解创建responseConvert
private Converter createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
==========>
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++) {
Converter converter =
//寻找转化工厂
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter) converter;
}
}
}
==========>Gson转化工厂,并不需要注解参数
@Override
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
{%endcodeblock%}
- step3:通过遍历注解数组并进行解析。
{%codeblock%}
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
通过上面ServiceMethod的构造,我们可以知道一个接口函数的网络的请求在这个ServiceMethod中会被重新拼接成一个网络的url请求,并存储了对应的callAdapter和converter工厂。
retrofit构建的过程:
public Builder() {
//这个platform.get就是获取当前使用retrofit所在的平台,默认为android,还有java和ios
this(Platform.get());
}
====>this
Builder(Platform platform) {
this.platform = platform;
//此时会先添加一个内置的转化convert,这样可以预防覆盖它的表现而且可以确保在转化各种类型时能够表现正确。
converterFactories.add(new BuiltInConverters());
}
在这个内置的BuiltInConverters内中,内置了几种默认的转化:
- StreamingResponseBodyConverter: 流转化
static final class StreamingResponseBodyConverter
implements Converter {
static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
return value;
}
}
直接返回整个流对象
- BufferingResponseBodyConverter:buffer转化
static final class BufferingResponseBodyConverter
implements Converter {
static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
@Override public ResponseBody convert(ResponseBody value) throws IOException {
try {
// Buffer the entire body to avoid future I/O.
return Utils.buffer(value);
} finally {
value.close();
}
}
}
将流读取成buffer对行返回
- VoidResponseBodyConverter: 空转化
static final class VoidResponseBodyConverter implements Converter {
static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();
@Override public Void convert(ResponseBody value) throws IOException {
value.close();
return null;
}
}
直接返回空对象null
正因为内置的只有这几种解析,所以通常我们在构建retrofit实例的时候需要我们主动的添加conver工厂。
protected Retrofit createRetrofit(String baseUrl) {
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(createOkHttpClient())
.addConverterFactory(GsonConverterFactory.create(createGsonConverter()))
.build();
}
这个GsonConverterFactory也就retrofit提供的gson对象转化工具,不过需要我们显式的添加到转化工厂中。最后调用build方法真正的构建实例:
public Retrofit build() {
...
//如果在配置项中有调用addClient的话,则将这个client作为call工厂,否则创建一个。
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//如果在配置项中有调用addExecutor,则将这个excutor作为callBack的excutor,否则创建一个默认的。
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 创建一个adpater工厂列表,并且平台默认的adapter工厂添加到里面
List adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 创建一个转化工厂列表,并且把默认的转化工厂添加到里面
List converterFactories = new ArrayList<>(this.converterFactories);
//此时调用构造函数做一些简单的赋值操作
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
在build完成之后,我们需要调用create方法,其中需要传入我们定义的网络请求的interface类。这个方法就是整个retrofit的入口,非常重要。
public T create(final Class service) {
//在这里会判断传入的service是否是一个接口。
Utils.validateServiceInterface(service);
if (validateEagerly) {
//这里会将service转化为ServiceMethod,这个非常重要,在retrofit中每一个接口请求都会被转化为ServiceMethod
eagerlyValidateMethods(service);
}
//step1:
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class>[] { service },
new InvocationHandler() {
//获取当前的应用平台
private final Platform platform = Patform.get();
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
if (method.getDeclaringClass() == Object.class) {
//如果该方法所在的类和我们代理类一样,则invake这个方法
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
//在android里面默认返回false,即一直不回抛异常
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//step2:在这里从缓存中读取serviceMethod,假如没有,那么创建
ServiceMethod serviceMethod = loadServiceMethod(method);
//step3:创建okHttp
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//step4:生成callAdapter,返回的是Call
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
- step1中,首先用了动态代理模式,返回这个Service所对应的代理对象,用于后续网络请求的拦截。Proxy.newProxyInstance是动态代理必要的方式,需要的参数为代理类的类加载器,代理类的实例和实现动态代理所需要实现的InvocationHndler接口,这个接口主要是用来在代理类上invoke方法的,也就是需要拦截的方法。需要传入的参数也基本是固定的,代理类,拦截的方法名和拦截的参数
- step2:在这里会对我们所需要invke的方法创建出对应的serviceMothod。
- step3:在我们对invoke的方法创建出serviceMethod之后,此时需要创建OkHttpCall,okHttpCall就包含了serviceMethod和方法参数。这个类主要是用来跟OkHttp进行对接的。因为内部真正的网络请求实际上是封装了okHttp。
- step4:在这里会将我们添加的okHttpCall添加到serviceMethod的callAdapter中,然后返回一个真正call的一个委托。
我们先来看看eagerlyValidateMethods这个方法:
private void eagerlyValidateMethods(Class> service) {
//获取当前的调用平台
Platform platform = Platform.get();
//对这个service接口里面的所有方法进行便利
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
//这个判断一直为false,即对于每一个service中的方法,都会调用一次loadServiceMethod
loadServiceMethod(method);
}
}
}
======>loadServiceMethod
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
//serviceMethodCache是一个缓存区,是用LinkedHashMap实现的,里面存放了接口的方法和其转化后ServiceMothod的映射
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//如果在缓存区中获取不到serviceMethod,那么进行创建。
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
retrofit请求过程
enqueue表示异步执行retrofit,excute表示同步执行retorfit,我们从enqueue的代码进行请求分析。通常的代码调用是这样的:
//这个是官网的调用过程
Call> repos = service.listRepos("octocat");
repos.enqueue(callback);
========>
@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 {
//step1:在这里创建出网络请求
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//在这里进入okhttp3的请求,在callBack中获取流式repsonse
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response response;
try {
//在这里进行解析
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
//解析没出现异常,则表示此次网络请求成功,在内部执行callback回调哟
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 response) {
try {
//执行传入的callback回调,并把解析的返回值回传
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
我们来看看是retrofit如何创建出okhttp的call
private okhttp3.Call createRawCall() throws IOException {
//直接将servicemethod转化为request,这一个步骤只有在调用的时候才会执行
Request request = serviceMethod.toRequest(args);
//生成CallFactory生成带有此次网络请求的call
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
retrofit解析网络返回过程
在执行enqueue方法中,有一个parseResponse(rawResponse)进行类型解析。因为okHttp只执行网络请求,并不会对返回的流进行类型转换转处理。下面我们来看看这个方法:
Response parseResponse(okhttp3.Response rawResponse) throws IOException {
//获取网络返回的body,也就的返回的json的data节点
ResponseBody rawBody = rawResponse.body();
//生层不带内容的response,用来判断网络请求是否正确返回
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
//小于200的返回码和大于300的返回码都被认为是错误的
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
//网络返回code204或者205表示网络请求返回为空。
return Response.success(null, rawResponse);
}
//去除了异常请求,现在就是正常解析了。
//创建委托类,为了不修改原类。
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//调用serviceMethod的转化
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
我们前面有提到,retrofit初始化时给每个方法生成了ServiceMethod,里面就存储了该请求的返回值类型。我们来看看这个toResponse的转化:
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
其实就是调用了内部的converter的convert方法,通常也是GsonConverter的conver方法。
总结
到这里,其实整个retrofit的网络请求从创建到访问再到解析的过程就结束了。最主要的两个地方就是ServiceMethod的创建和retrofit的动态代理机制。下面添加一张随便画的流程图哈:
[图片上传失败...(image-391ae-1542202625517)]