问题:
1、什么是Retrofit?
2、为什么要用Retrofit?
3、Retrofit原理?
问题1:什么是Retrofit?
Retrofit是squareup公司开源的一个网络请求工具框架,是一种用于Android和java进行网络请求的类型安全客户端。简单理解就是它是一种用于网络请求的工具框架,仅适用于Android和java。
细心的同学会提出疑问怎么是网络请求工具而不是网络请求呢?其实Retrofit对okhttp进行封装,方便网络请求的调用,真正实现网络请求的是okhttp,进行原来解析时会进行应证。
问题2:为什么要用Retrofit?
1、okhttp进行网络请求相对而言偏底层,使用还是比较麻烦,而Retrofit就是为了简便使用okhttp而开发的工具框架,Retrofit还提供了对请求、响应、okhttpclient等进行扩展
2、Retrofit实现了Restful api的设计风格
问题3:Retrofit原理
下面先对Retrofit核心源码进行解析,再对Retrofit原理进行总结:
使用Retrofit时,一般都是先build一个Retrofit实例:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(HttpConst.HOST)
.addConverterFactory(CustomGsonConverter.create(new GsonBuilder()
.disableHtmlEscaping()
.create()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(buildOkHttp(builder))
.build();
3.1、我们看下Retrofit.Builder的build方法
public Retrofit build() {
//http url前缀,一般是域名
if (baseUrl == null) {
//如果baseUrl为空则抛出异常
throw new IllegalStateException("Base URL required.");
}
//callFactory的实现类是OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//如果callFactory 为空则创建一个默认的OkHttpClient
callFactory = new OkHttpClient();
}
//http响应回调执行器
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//callbackExecutor为空,则使用平台的默认回调执行器
callbackExecutor = platform.defaultCallbackExecutor();
}
//网络请求适配器工厂类,并添加平台的默认请求请求适配器工厂类
// Make a defensive copy of the adapters and add the default Call adapter.
List callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//网络响应内容解析工厂类,并添加BuiltInConverters
// Make a defensive copy of the converters.
List converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//根据配置参数,构建Retrofit
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
上面的代码,可以总结构建Retrofit可配置的主要参数有:
a、baseUrl:http url 前缀,一般是域名,这个是必现要配置的
b、OkHttpClient: 可以不配置,如果配置了必现不为空,如果没有配置则默认创建一个新的OkHttpClient
c、callAdapterFactory: http请求适配器工厂类
d、converterFactory: http网络请求响应内容解析工厂类
3.2、build方法代码中有个platform,我们看下其实现:
public Builder() {
this(Platform.get());
}
Builder(Retrofit retrofit) {
platform = Platform.get();
//....省略
}
Platform.get的实现:
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
findPlatform方法的实现:
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();
}
findPlatform方法是确定当前是Android还是java,它首先尝试调用Android的API,如果是Android则创建Android平台对象并返回;否则创建Java平台并返回
3.3、Retrofit的create方法
一般创建Retrofit之后,就通过create创建api请求的代理类,我们看下create方法的实现:
/**
@params service 网络请求代理类接口
*/
public T create(final Class service) {
//校验service是接口类型并且没有父类
Utils.validateServiceInterface(service);
//预加载接口方法,并缓存
if (validateEagerly) {
eagerlyValidateMethods(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, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
//如果是Object对象,则直接调用Object的方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//如果调用的是默认方法,直接调用
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//对网络请求方法进行包装生成ServiceMethod
ServiceMethod
上面的代码我们可以看到Retrofit的create方法,使用了动态代理的机制,动态的创建网络请求接口的代理类,通过生成的代理类调用接口方法发起网络请求会进入InvocationHandler的invoke方法,在invoke方法中使用serviceMethod.adapt进行网络请求。
3.4、我们看下ServiceMethod的构建过程build方法:
public ServiceMethod build() {
//创建网络请求适配器callAdapter
callAdapter = createCallAdapter();
//获取网络请求响应内容属类型
responseType = callAdapter.responseType();
//网络请求响应内容不允许是Response和okhttp3的response对象
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();
//解析api注解信息,得到url、头部、请求内容等
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//retrofit语义解析,如果请求方法不是get\post\head\delete等则抛出异常
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
//retrofit语义解析,如果没有内容体而实际又有则抛出异常
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
//注解中请求参数个数
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.");
}
//从注解中解析出http头部
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
//相对路径为空抛出异常
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
//使用了form或者multipart,而没有body则抛出异常
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
//使用了form而没有field则抛出异常
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
//使用了multipart而没有part则抛出异常
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
//创建ServiceMethod对象
return new ServiceMethod<>(this);
}
ServiceMeothd的构建过程主要有:
- 创建网络请求适配器callAdapter
- 解析出网络请求的返回类型
- 创建网络请求响应内容解析器responseConverter
- 对请求Api方法进行解析,解析的内容是获取方法中注解信息
- 然后对解析出的注解内容进行Retrofit的语义校验和解析,包括:请求方法是否合法、语法是否正确、解析出http头部和请求参数列表等
接着是使用ServiceMethod的adapt进行网络请求,我们看看adapt的实现:
T adapt(Call call) {
return callAdapter.adapt(call);
}
adapt的实现是调用网络请求适配器callAdapt的adapt方法进行网络请求
3.5、我们看下callAdapter的创建实现:
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 {
//noinspection unchecked
//通过Retrofit的callAdapter发放创建CallAdapter
return (CallAdapter) 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);
}
}
我们继续看Retrofit的callAdapter方法是如何创建CalllAdapter的:
public CallAdapter, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
Retrofit的callAdapter方法调用nextCallAdapter来创建CallAdapter的,我们继续nextCallAdapter的实现:
public CallAdapter, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
//校验网络请求接口方法的返回类型不能为空
checkNotNull(returnType, "returnType == null");
//校验网络请求接口方法的注解不能为空
checkNotNull(annotations, "annotations == null");
//遍历callAdapterFactories,使用其工厂类进行创建,哪个创建成功则直接返回
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;
}
}
//无法创建callAdapter抛出异常
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());
}
nextCallAdapter使用CallAdapter工厂类的实现类的get方法进行创建CallAdapter的,我们一般用的是RxJava2CallAdapterFactory,所以我们直接看RxJava2CallAdapterFactory的get方法实现
3.6、RxJava2CallAdapterFactory的get方法实现
@Override
public CallAdapter, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//获取网络请求接口方法的返回类型的泛型,比如Flowable>,则返回Flowable
Class> rawType = getRawType(returnType);
//判断返回类型是否是Completable
if (rawType == Completable.class) {
// Completable is not parameterized (which is what the rest of this method deals with) so it
// can only be created with a single configuration.
return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
false, true);
}
//返回类型是否是Flowable
boolean isFlowable = rawType == Flowable.class;
//返回类型是否是Single
boolean isSingle = rawType == Single.class;
//返回类型是否是Maybe
boolean isMaybe = rawType == Maybe.class;
if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
return null;
}
boolean isResult = false;
boolean isBody = false;
Type responseType;
//如果返回类型不是合法的泛型则抛出异常
if (!(returnType instanceof ParameterizedType)) {
String name = isFlowable ? "Flowable"
: isSingle ? "Single"
: isMaybe ? "Maybe" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + " or " + name + " extends Foo>");
}
//返回返回类型的上界,其实就是Response>,比如Flowable>则返回Response
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
//获取泛型的类型,比如Response则返回Response
Class> rawObservableType = getRawType(observableType);
if (rawObservableType == Response.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Response must be parameterized"
+ " as Response or Response extends Foo>");
}
//获取http响应内容类型,比如Response则返回String
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
} else if (rawObservableType == Result.class) {
if (!(observableType instanceof ParameterizedType)) {
throw new IllegalStateException("Result must be parameterized"
+ " as Result or Result extends Foo>");
}
responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
//返回内容是Result
isResult = true;
} else {
responseType = observableType;
//返回内容是body类型
isBody = true;
}
//创建RxJava2CallAdapter
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
RxJava2CallAdapterFactory的get返回创建Rxjava2CallAdapter的过程是:
- 对返回类型进行一层一层泛型的校验和解析
- 得到返回类型对应的RxJava类型信息,比如:是否是Flowable、Single、Maybe、Result、body等
- 创建Rxjava2CallAdapter
3.7、我们看RxJava2CallAdapter的adapt实现:
回到网络请求的流程,上面分析到网络请求是调用callAdapter的adapt方法,而我们一般配套使用的是Rxjava,而Rxjava中RxJava2CallAdapter是callAdapter的真实实现类,所有我们接下来看下RxJava2CallAdapter的Adapt方法:
@Override public Object adapt(Call call) {
//判断是否使用异步,异步我们使用的是异步实现
Observable> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
//根据3.6中解析出的Rxjava对应类型,是Flowable、Single、Maybe、Result、Body、Response,创建对应的Observable,我们一般使用的是Response
Observable> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
//设置observable subscribe在哪个线程
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
//设置背压处理方式,Flowable采用的是只保留最后的结果
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
Rxjava2CallAdapter的adapt只是构建observable,并返回observalbe,其对网络的请求是通过CallEnqueueObservable实现的
3.8、CallEnqueueObservable的实现
@Override protected void subscribeActual(Observer super Response> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call call = originalCall.clone();
CallCallback callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);
}
3.3中知道这里的originCall是OkHttpCall
3.9、OkHttpCall的enqueue实现
@Override
public void enqueue(final Callback callback) {
checkNotNull(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 {
//构建Okhttp的真实网络请求Call对象
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//这里就是okhttp的最原始调用
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response response;
try {
//对http响应内容进行解析
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();
}
}
});
}
OkHttpCall的enqueue方法先根据注解中的信息、请求参数构建出okhttp真实的网络请求Call对象,接下来就是okhttp最原始的使用方式了,至于call是如何构建的,这里就不展开说明。
我们看到网络请求响应内容经过parseResponse方法进行解析,下面我们看下其实现。
3.10、网络响应内容解析parseResponse方法的实现
Response 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.
//重新构建响应体,这个心的响应体不包含body内容,是为了方便传递
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
//获取http响应状态码
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);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//调用serviceMethod的toResponse方法进行解析
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;
}
}
上面的代码告诉我们真正的解析是通过ServiceMethod的toResponse方法进行解析的,接下来我们看下其实现:
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
ServiceMethod中通过responseConverter进行解析响应内容。
至此,我们已经解析完Retrofit的具体实现原理,我们可以梳理总结为:
- 使用构建模式创建Retrofit实例对象
- 使用动态代理模式,通过Retrofit实例对象的create方法动态创建网络请求接口的代理类
- 使用代理类调用方法发起网络请求时,会通过CallAdapterFactory创建的CallAdapter对象的adapt方法调用OkHttpCall的enqueue方法发起网络请求
- OkHttpCall的enqueue方法先根据注解、请求参数等信息构建出OkHttpClient的网络请求Call对象,接着使用Call对象发起网络请求
- 网络请求回来时,使用ServiceMethod的toResponse方法中调用响应内容适配器的具体实现类的convert发放进行解析
Retrofit只是对网络请求进行封装的一个框架,它本身并不发起网络请求,为的是方便我们使用、优化我们网络请求的代码、对网络请求进行扩展(可以自定义请求适配器、响应内容解析器等)。
最后使用Retrofit需要注意一下细节:
- 必须要要配置baseUrl
- 定义网络请求必须是接口不能是类,且不能继承其他的接口
- 定义网络请求接口时,必须要遵循Retrofit的语义规则,比如:@GET对应@Query;@FormUrlEncoded对应@Field;@Multipart对应@Part等
- 如果配套使用Rxjava,则必须遵循RxJava语义
- 对应OkHttp头部的key不能null也不能为空字符串;value不能为null