retrofit是square公司基于okhttp,okio之上的又一款非常好的开源库。该库主给android/java开发者提供了简化而优美的http实现接口。开发成员可以将http api通过注解的方式写入到interface中,然后通过接口调用的方式发起http请求。而且retrofit提供了丰富的converters,可以方便RequestBody,ResponseBody类型的转换机制,以及对call的adapter机制大大方便了用户对于网络请求的使用。官网地址为:retrofit

重要的类和字段功能

retrofit 注解

retrofit的其中一个特点是,允许用户将http api通过注解的方式写入到一个interface之中。retrofit提供的注解的生命周期全部是RUNTIME级别,意味着都是在运行时进行注解解析配置的。这一点和ButterKnife不一样。retrofit提供的注解主要有以下几类

  1. http method部分
    GET, POST, PATCH, PUT, DELETE, HEAD, OPTIONS, HTTP
    这些注解中,都支持填入path,该path最终和retrofit中设置的base url一起组成完整的url。其中注解HTTP比较特殊,HTTP支持自定义method。

    1
    2
    3
    4
    5
    6
    7
    8
    @Documented
    @Target(METHOD)
    @Retention(RUNTIME)
    public @interface HTTP {
    String method();
    String path() default "";
    boolean hasBody() default false;
    }
  2. head部分
    如果需要对所有http访问请求都需要添加统一的header,可以通过okhttp的Interceptor实现。如果针对某些个具体的http api才需要添加的header可以使用retrofit的Header/Headers/HeadMap注解,例如:

    1
    2
    3
    4
    5
    6
    @Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
    })
    @GET("users/{username}")
    Call<User> getUser(@Path("username") String username);
  3. path, query部分
    在http method的注解中填入的path可以是不完整的。可以在函数的参数列表中,通过Path注解进行参数指定,同时可以选择是否encode
    对于url中的的query部分,可以通过注解Query/QueryMap/QueryNam进行指定

  4. body部分
    考虑到body部分可以多种多样的类型,因此这一部分的注解比较庞杂,包括:Body, Field, FieldMap, FormUrlEncoded, Multipart, Part, PartMap

  5. response部分
    retrofit提供注解Streaming指明返回类型没有经过任何转换,保持为okhttp的ResponseBody

Converter<F,T>

用于转换类型从类型F转变成T,这个类非常用于,被retrofit用于转换requestBody和responseBody,而且用户可以配置自己所需转换的类型。
下面给出Converter的核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface Converter<F, T> {
T convert(F value) throws IOException;
abstract class Factory {
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
//stringConverter主要用于转变service interface中param到string类型
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
...
}
}

CallAdapter<R, T>

和Converter类似,用于将一个类型转换到另一个,不过CallAdapter主要用于转换Call<R>到T
下面给出其核心代码

1
2
3
4
5
6
7
8
9
10
11
public interface CallAdapter<R, T> {
Type responseType();
T adapt(Call<R> call);
abstract class Factory {
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
......
}
}

BuiltInConverters

在调用Retrofit.Builder过程中,Builder已经默认添加上了BuiltInConverters。该类用于提供默认的converter,帮助将原始的ResponseBody,RequestBody转换到指定的类型,下面给出部分核心代码,代码很简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
final class BuiltInConverters extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == ResponseBody.class) {
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
return RequestBodyConverter.INSTANCE;
}
return null;
}
......
}

ExecutorCallAdapterFactory

在android平台下,Retrofit.Builder build过程中生成一个ExecutorCallAdapterFactory添加到Retrofit中。该类的主要目的是,替换Call,在Call的enqueue过程中,确保最终response返回白执行在指定的executor中。
该类正常情况下位于Retrofit的adapterFactories list的最后一个,正式为了确保最终callback在executor中执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@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<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
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(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
......
}

ParameterHandler

ParameterHandler的主要作用是提供apply方法,根据method的输入值构建okhttp的RequestBuilder,下面给出ParameterHandler的部分代码

1
2
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, @Nullable T value) throws IOException;

可以看出子类需要实现apply方法来实现对RequestBuider的配置
有意思的是,该类中,还提供了array和iterable的变形,方便处理批量的T类型数据到RequestBuilder中,下面给出部分代码

1
2
3
4
5
6
7
8
9
10
11
12
final ParameterHandler<Iterable<T>> iterable() {
return new ParameterHandler<Iterable<T>>() {
@Override void apply(RequestBuilder builder, @Nullable Iterable<T> values)
throws IOException {
if (values == null) return; // Skip null values.
for (T value : values) {
ParameterHandler.this.apply(builder, value);
}
}
};
}

由该类延伸出很多子类,例如RelativeUrl, Header等等,下面仅仅给出部分子类代码仅供参考

1
2
3
4
5
6
static final class RelativeUrl extends ParameterHandler<Object> {
@Override void apply(RequestBuilder builder, @Nullable Object value) {
checkNotNull(value, "@Url parameter is null.");
builder.setRelativeUrl(value);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static final class Header<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
Header(String name, Converter<T, String> valueConverter) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String headerValue = valueConverter.convert(value);
if (headerValue == null) return; // Skip converted but null values.
builder.addHeader(name, headerValue);
}
}

ServiceMethod

对于service interface中的method主要解析工作都放在了该类中。

Builder

对于method的parse工作主要在Builder的build方法中进行, build的工作主要为:

  1. callAdapter
    根据method的returnType从retrofit的adapterFactories中寻找合适的callAdapter,并保存该callAdapter的索引
  2. responseConverter
    根据callAdapter的responseType,从retrofit的converterFactories中寻找并生成对应的responseConverter
  3. method annotations
    解析method上的每一个注解,并将解析结果保存在对应的字段中
  4. parameter annotations
    解析每一个method parameter上的注解,生成parameter上对应ParameterHandler<?>

toRequest

ServiceMethod在toRequest中,生成okhttp的ReqeustBuilder,并通过ParameterHanders处理每一个输入参数的值,从而完成对RequestBuilder配置,最后上传okhttp的Request。过程非常简洁,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Request toRequest(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}

Retrofit

Builder

可以通过Retrofit.Builder内部类对Retrofit进行初始化,通过builder可以配置一些重要的参数,例如

  1. OkHttpClient, 用于提供callFactory
  2. callFactory, 用于提供newCall接口,一般为okHttpClient实例
  3. baseUrl, 可以控制所有api的base url
  4. Converter.Factory, 用于控制requestbody,responsebody类型转换
  5. CallAdapter.Factory, 用于控制Call<>类型的转换
  6. CallbackExcecutor, 可以控制callback执行线程,默认为platform的defaultCallbackExcecutor,即android的主线程

serviceMethodCache

该字段类型: Map <<Method, ServiceMethod<?, ?>>,用于缓存解析过的method

<T>T create(class<T> service)

该method主要用于将包含用户定义的service interface进行实例化。实例化之前,如果用户配置了validateEagerly=true,则立即解析service interface中的所有注解,解析过程中,每一个method对应一个ServiceMethod。并将结果保存在serviceMethodCache中

在实例化service interface时,使用了java的proxy代理机制,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public <T> T create(final Class<T> 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.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

OkhttpCall

该类实现了Call<T>接口, 实际上该类是对okhttp call的一个封装。内部通过rawCall属性指向实际call对象。

1
2
3
4
5
6
7
8
9
10
11
......
rawCall = createRawCall();
......
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}

大部分操作通过rawCall对象进行,okHttpCall的任务是将执行结果封装成response对象,并在封装过程中,执行类型转换。下面代码给出了enqueue的部分代码,以及封装response的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@Override public void enqueue(final Callback<T> 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 {
call = rawCall = createRawCall();
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@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();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
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;
}
}