Retrofit2 源码解读

基本概念

Retrofit 是一个针对Java/Android类型安全的Http请求客户端。
基本使用如下:

  1. 首先定义一个接口,抽象方法的返回值必须为Call<XX>

    1
    2
    3
    4
    public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);//默认CallAdapter返回值必须为`Call<XX>`。
    }
  2. 通过Retrofit的create创建接口实现

    1
    2
    3
    4
    5
    6
    7
    8
     //初始化Retrofit
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/") //必须以斜杠结尾
    .addConverterFactory(GsonConverterFactory.create())//添加Gson转换工厂
    .build();

    //通过Retrofit创建接口实现
    GitHubService service = retrofit.create(GitHubService.class);
  3. 接口调用相关方法获取Call<XX>,然后就能和Okhttp一样进行同步/异步调用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Call<List<Repo>> repos = service.listRepos("octocat");
    //异步调用
    repos.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
    List<String> list=response.body();//调用body()
    }

    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {

    }
    });
    //同步调用
    Response<List<Repo>> response=repos.execute();

源码解读

Retrofit中的相关注解

请求方法注解

该类注解用于指明请求方法,在使用时必须指定且只可指定一种请求方法。

  1. @GET

    用来指明请求方法和相对/绝对/完整路径。当然也可以配合@Url使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public interface RequestService {
    @GET("xx/xxx") //指定相对路径
    Call<ResponseBody> getContent1();

    @GET("/xxx") //指定绝对路径,相对路径和绝对路径的区别见后文
    Call<ResponseBody> getContent1();

    @GET("http://www.baidu.com") //指定完整Url
    Call<ResponseBody> getContent2();

    @GET //配合@Url使用,此时@GET只能指明请求方法,路径参数必须留空
    Call<ResponseBody> getContent3(@Url String url);
    }
  2. @POST

    用来指明请求方法和相对/绝对/完整路径,同时也可以配合@Url使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public interface RequestService {
    @POST("xx/xxx") //指定相对路径
    Call<ResponseBody> getContent1();
    @POST("/xxx") //指定绝对路径
    Call<ResponseBody> getContent1();
    @POST("http://www.baidu.com") //指定完整Url
    Call<ResponseBody> getContent2();

    @POST //配合@Url使用,此时@POST只能指明请求方法,路径参数必须留空
    Call<ResponseBody> getContent3(@Url String url);
    }
  3. @DELETE,@HEAD,@OPTIONS,@PATCH,@PUT

    这几种请求方法和POST/GET在使用上没有太大区别,由于不太常用,这里就不做介绍。

请求参数注解

  1. @Path
    该注解用于替换Url的路径(path)部分。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public interface RequestService {
    @GET("/image/{id}") //替换{}内的路径
    Call<ResponseBody> getImage(@Path("id") int id);

    @GET("/user/{name}") //替换{}内的路径
    Call<ResponseBody> getUserInfo(@Path("name") String name);

    @GET("/user/{name}") //替换{}内的路径,encoded=true则表示自己处理编码,
    Call<ResponseBody> getUserInfo(@Path(value="name", encoded=true) String name);

    }

    上述代码有一个是否需要编码的问题,这里举个例子:假如输入名字maple+jaw,默认情况下为GET中的注解为/user/maple%2Bjaw,如果指明自己处理编码,此时输入maple+jaw,路径参数为/user/maple+jaw

  2. @Query
    该注解用于在Url后追加查询参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public interface RequestService {
    @GET("/list") //追加查询参数后,此时路径为/list?page=xx
    Call<ResponseBody> getList(@Query("page") int page);

    @GET("/list") //追加查询参数后,此时路径为/list?page=xx&category=xx
    Call<ResponseBody> getList(@Query("page") int page,@Query("category") String category);

    @GET("/list") //同理也可指定是否编码
    Call<ResponseBody> getList(@Query(value="category",encoded=true) String category);

    }
  3. @QueryMap
    @QueryMap和@Query的作用是一样的,只不过@QueryMap是以map的形式追加参数,可以一次性追加多个参数

    1
    2
    3
    4
    5
    public interface RequestService {
    @GET("/search")
    Call<ResponseBody> getList(@QueryMap Map<String, String> filters);

    }
  4. @Field
    该注解用于添加表单数据,须配合@FormUrlEncoded一起使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public interface RequestService {
    @FormUrlEncoded
    @POST("/register") //使用@Field提交表单数据
    Call<ResponseBody> register(@Field("name") String name,@Field("password") String pwd,);

    @FormUrlEncoded
    @POST("/register") //使用@Field提交表单数据,encoded=true表示该数据自己编码
    Call<ResponseBody> register(@Field(value="name",encoded=true) String name,@Field("password") String pwd,);

    }
  5. @FieldMap
    @Field和@FieldMap的作用一样,后者以map的方式提交表单数据

    1
    2
    3
    4
    5
    6
    public interface RequestService {
    @FormUrlEncoded
    @POST("/register") //使用@FieldMap提交表单数据
    Call<ResponseBody> register(@FieldMap Map<String, String> fields);

    }
  6. @Header
    该注解用于指明请求头参数,相同名字的请求头是惟一的,新的会直接覆盖旧的。

    1
    2
    3
    4
    5
    6
    public interface RequestService {
    @GET("/")
    Call<ResponseBody> getContent(@Header("Accept-Language") String lang
    ,@Header("Cache-Control") String cache);


    }
  7. @Headers
    该注解用于指明请求头参数,和@Header的区别在于不会覆盖掉相同名字的请求参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public interface RequestService {
    @Headers("Cache-Control: max-age=640000")
    @GET("/")
    Call<ResponseBody> getContent();


    @Headers({"Cache-Control: max-age=640000""Accept-Language: gzip, deflate"})
    @GET("/")
    Call<ResponseBody> getContent();

    }
  8. @HeaderMap
    @HeaderMap和@Headers的作用一样,区别在于以Map的形式指明请求头参数。

    1
    2
    3
    4
    5
    public interface RequestService {
    @GET("/search")
    Call<ResponseBody> getList(@HeaderMap Map<String, String> headers);

    }
  9. @Part
    该注解用于定义分块表单请求中的块。需配合@Multipart一起使用。
    如果类型是MultipartBody.Part,内容将直接被使用。(@Part MultipartBody.Part part
    如果类型是RequestBody,将会和它的contentType一起使用。(@Part("foo") RequestBody foo
    其他类型将会通过转换器转换后使用。(@Part("foo") Image photo
    @Part(XX),XX表示表单名。

    1
    2
    3
    4
    5
    6
    7
     public interface RequestService {
    @Multipart
    @POST("/")
    Call<ResponseBody> example(@Part("description") String description,
    @Part(value = "image", encoding = "8-bit") RequestBody image);


    }
  10. @PartMap
    和@Part的作用一样,区别在于以Map的形式定义,其中Map的Value类型转换同@Part。

    1
    2
    3
    4
    5
    6
    7
     public interface RequestService {
    @Multipart
    @POST("/upload")
    Call<ResponseBody> example(@Part("file\"; filename=\"test.txt") RequestBody file,
    @PartMap Map<String, RequestBody> params);


    }
  11. @Body
    当请求体不是表单/分块类型时,该注解用于直接指定请求体。请求体内部转换时通过Converter转换为RequestBody实现的。

    1
    2
    3
    4
    5
     public interface RequestService {
    @POST("/upload")
    Call<ResponseBody> example(@Body String conent);

    }
  12. @HTTP
    该注解用于自定义请求。

    1
    2
    3
    4
    5
    6
    7
      interface Service {
    @HTTP(method = "DELETE", path = "remove/", hasBody = true)
    Call<ResponseBody> deleteObject(@Body RequestBody object);

    @HTTP(method = "CUSTOM", path = "custom/endpoint/")
    Call<ResponseBody> customEndpoint();
    }
  13. @Streaming
    使用该注解后,将不会缓冲流到内存中,只在返回类型为Call<ResponseBody>时起效。如果使用Retrofit下载大文件,务必要加上该注解。

Retrofit构造

按照老规矩,从Retrofit的构造方法下手,要想了解Retrofit的构造方法,必须先了解以下几个类

Call接口

注意,此Call非Okhttp中的Call,结构如下,通过Call可以进行同步和异步请求,还能判断取消与否。
image_1ank3mstmho91qum9k646415a29.png-20.2kB

CallAdapter

CallAdapter主要用来代理call(默认为OkhttpCall)以方便实现自己想要的功能,比如RxJavaCallAdapter等。可以通过Retrofit.Builder#addCallAdapterFactory(Factory)来添加CallAdapterFactory。

1
2
3
4
5
6
7
8
9
10
public interface CallAdapter<T> {

//返回响应类型,即Call<Repo>的响应类型为Repo
Type responseType();

//返回一个代理call的实例。
<R> T adapt(Call<R> call);
//..
//省略了工厂源码,用于获取CallAdapter的实例
}

Callback

Callback用于回调结果。

1
2
3
4
5
6
7
8
public interface Callback<T> {

//接收HTTP响应(404,500也会调用,所以需要调用isSuccessful来判断)
void onResponse(Call<T> call, Response<T> response);

//网络异常或者发生异常时调用
void onFailure(Call<T> call, Throwable t);
}

Converter

用于类型转换,使用Retrofit.Builder#addConverterFactory(Factory)添加转换工厂,比如添加Gson转换。

1
2
3
4
5
public interface Converter<F, T> {
T convert(F value) throws IOException;
//..
//省略了工厂源码
}

构造方法

Retrofit构造方法采用构建者模式构造,源码如下。

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
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();//key为接口中定义方法,value为转换过后的方法

public static final class Builder {
private Platform platform;//平台:安卓、java等
private okhttp3.Call.Factory callFactory; //okhttp的Call工厂类,自定义newCall将Request转为Call
private HttpUrl baseUrl;//okhttp中的类,保存解析过的url
private List<Converter.Factory> converterFactories = new ArrayList<>();//类型转换工厂列表。
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();//CallAdapter工厂列表。
private Executor callbackExecutor;//回调线程池
private boolean validateEagerly;//急需验证?作用在于直接将所有方法加入前面的map缓存中。

Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());//添加默认的转换器
}

public Builder() {
this(Platform.get());//通过Platform.get()获取关于当前平台的实现
}

public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}

okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();//默认使用OkHttpClient
}

Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {//默认使用平台默认回调线程池
callbackExecutor = platform.defaultCallbackExecutor();
}

//将平台默认CallAdapter.Factory加入列表中
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

//将默认Converter.Factory加入列表中
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}

可以看出,首选通过Platform.get()来获取平台实现然后添加了默认转换工厂。由于我们是Android平台,毋容置疑,接下来就去看看Andoird类的源码。
image_1ank6t5fdqe51k5jm221ff116jjm.png-56.6kB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static class Android extends Platform {
//回调线程池
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();//主线程
}

@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
//ExecutorCallAdapterFactory继承CallAdapter.Factory,内部代理了原来的Call<T>,用于将Callback回调到指定线程中。
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);//采用Hanlder#post回调到主线程
}
}
}

Andoird类的源码主要实现了两个方法,一个是实现了默认的回调线程池,用于在主线程中执行任务,另一个是实现了CallAdapter工厂,通过代理的方式,将执行结果回调到callbackExecutor中去执行。所以,我们只需将callbackExecutor赋值为MainThreadExecutor即可实现主线程间的回调。

BuiltInConverters继承于Converter.Factory,Converter.Factory中有三个方法:

  • public Converter<ResponseBody, ?> responseBodyConverter(xx)用于将ResponseBody转换为指定类型,通常用于对响应结果的类型转换。
  • public Converter<?, RequestBody> requestBodyConverter(xx)用于将指定类型转为RequestBody。一般用于将@Body,@Part,@PartMap转为RequestBody
  • public Converter<?, String> stringConverter用于将指定类型转为String,用于将@Field,@FieldMap,@Path,@Query,@Header等注解的参数类型转为String。

BuiltInConverters源码实现如下:

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
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
//根据类型进行选择不同的转换器
if (type == ResponseBody.class) {//转换类型为ResponseBody
if (Utils.isAnnotationPresent(annotations, Streaming.class)) {
return StreamingResponseBodyConverter.INSTANCE;//如果使用了Steaming注解,就不缓冲到内存,直接返回OkHttp的ResponseBody。
}
return BufferingResponseBodyConverter.INSTANCE;//缓冲ResponseBody到内存后返回
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;//Void就直接关闭ResponseBody
}
return null;
}

@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {//默认只处理RequestBody相关类型
return RequestBodyConverter.INSTANCE;
}
return null;
}

@Override public Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == String.class) {//默认只处理String类型的转换,说白了就是直接返回
return StringConverter.INSTANCE;
}
return null;
}
//..
//省略了部分源码
}

BuiltInConverters源码中最重要的在于responseBodyConverter方法,如果转换类型是ResponseBody且有@Streaming注解,那么将不会缓冲到内存。你可能会疑问两者有什么区别?那么我们想象一种情景——下载大文件。如果下载大文件时将ResponseBody缓冲到内存,OOM那是分分钟的事。

Retrofit提供的用于自定义的方法如下:
image_1ank9trh8mavpd16n1l85nm513.png-27.5kB

  • client(OkHttpClient) 用于自定义客户端
  • callFactory(okhttp3.Call.Factory factory)用于自定义Call工厂,重写newCall将Request转为Call。OkHttpClient就是实现了这个接口。
  • addConverterFactory添加类型转换工厂(Gson转换等)
  • addCallAdapterFactory添加CallAdapter代理工厂,用来代理原始的Call(RxJavaCallAdapter等)。
  • callbackExecutor自定义回调线程池,默认为主线程
  • validateEagerly是否继续验证,是就提前将所有方法转为ServiceMethod放入缓存中,而不是调用一个缓存一个
  • baseUrl用于定义基本链接,必须以”/“结尾

假如基本地址为http://example.com/api/,关于baseUrl与注解中路径的拼接问题如下:

注解中的路径 最终Url (baseUrl为http://example.com/api/)
foo/bar/ http://example.com/api/foo/bar/
/foo/bar/ http://example.com/foo/bar/
https://github.com/square/retrofit/ https://github.com/square/retrofit/
//github.com/square/retrofit/ http://github.com/square/retrofit/

创建Service接口

介绍完构造方法后,我们再来看看retrofit.create(XX.class);这个方法。

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
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);//验证接口,接口不能有继承
if (validateEagerly) {
eagerlyValidateMethods(service);//将所有方法(跳过默认方法)转为ServiceMethod放入map中
}
//使用代理
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 {

//代理调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//JAVA8接口可以定义默认方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}

//直接看这里
//将普通的Method转为ServiceMethod
ServiceMethod serviceMethod = loadServiceMethod(method);
//将ServiceMethod以及传入的参数值传入OkHttpCall。
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//利用callAdapter代理OkHttpCall,默认直接返回。
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

retrofit.create(XX.class);方法中使用了Java代理,核心在于,首先将普通的Method转为ServiceMethod,然后将ServiceMethod以及传入的参数值传入到OkHttpCall中,最终通过代理OkHttpCall来返回代理Call,默认是直接返回。

ServiceMethod的创建

接下来,我们来看看是怎样将Method转为ServiceMethod的,源码在loadServiceMethod方法中:

1
2
3
4
5
6
7
8
9
10
11
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);//首先从map中取看看是否已经缓存过
if (result == null) {//否则构造ServiceMethod。
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);//缓存map中
}
}
return result;
}

loadServiceMethod的方法很简陋,直接传入了Method然后build(),那么这个build()又做了什么?

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
  public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();//赋值方法注解数组
this.parameterTypes = method.getGenericParameterTypes();//赋值参数类型数组
this.parameterAnnotationsArray = method.getParameterAnnotations();//赋值参数注解数组
}

public ServiceMethod build() {
callAdapter = createCallAdapter();//创建CallAdapter,用来代理Call
responseType = callAdapter.responseType();//获取返回类型
//...
responseConverter = createResponseConverter();//创建ResponseConverter,用来转换ResponseBody为指定类型

for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);//遍历解析方法注解
}
//...
int parameterCount = parameterAnnotationsArray.length;//parameterAnnotationsArray为参数注解数组
parameterHandlers = new ParameterHandler<?>[parameterCount];//初始化ParameterHandler,用来处理参数相关
for (int p = 0; p < parameterCount; p++) {//遍历参数注解数组
Type parameterType = parameterTypes[p];//获取参数类型
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];//获取参数注解数组
//...
//通过注解和参数类型,解析并赋值到parameterHandlers中
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}

//...

return new ServiceMethod<>(this);
}

createCallAdapter用于创建CallAdapter。最终的源码在Retrofit类中,从源码可以看出,进行遍历源码,如果查询到就返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");

int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
//遍历Adapter集合,查到就返回
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
//..
//省略了部分源码
}

同理,createResponseConverter也是。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations)
{

checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");

int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
//遍历调用查询
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter<ResponseBody, T>) converter;
}
}

//..
//省略了部分源码
}

parseMethodAnnotation用于遍历解析方法上的注解,比如请求方法,请求头之类的。

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
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 = (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);//解析Header
} else if (annotation instanceof Multipart) {
//Multipart
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
//FormUrlEncoded
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}

从上面源码可以看出,使用parseHttpMethodAndPath这个方法用于解析请求方法注解和路径参数保存到Set中

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
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;

if (value.isEmpty()) {
return;
}


int question = value.indexOf('?');//查询参数开始的符号
if (question != -1 && question < value.length() - 1) {
//如果在查询参数中使用了{},则抛出异常。
String queryParams = value.substring(question + 1);
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
if (queryParamMatcher.find()) {
throw methodError("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}

//赋值相对链接
this.relativeUrl = value;
//解析{}路径参数保存到Set中
this.relativeUrlParamNames = parsePathParameters(value);
}

从源码可以发现,不允许在查询参数中使用{}进行占位,否则就会抛出异常,然后将请求方法中的注解值赋值给relativeUrl,通过parsePathParameters将{}路径参数保存到Set中。
通过parseHeaders来解析头部注解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private Headers parseHeaders(String[] headers) {
Headers.Builder builder = new Headers.Builder();
for (String header : headers) {
int colon = header.indexOf(':');
if (colon == -1 || colon == 0 || colon == header.length() - 1) {
throw methodError(
"@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
}
String headerName = header.substring(0, colon);
String headerValue = header.substring(colon + 1).trim();
if ("Content-Type".equalsIgnoreCase(headerName)) {
MediaType type = MediaType.parse(headerValue);
if (type == null) {
throw methodError("Malformed content type: %s", headerValue);
}
contentType = type;
} else {
builder.add(headerName, headerValue);
}
}
return builder.build();
}

看完解析方法注解后,现在来看下是如何解析参数相关注解的。源码在parseParameter

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
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {//遍历参数注解
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);//解析参数注解

if (annotationAction == null) {
continue;
}

if (result != null) {
//一个参数中只允许使用一个注解,否则抛出异常
throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
}

result = annotationAction;
}

if (result == null) {
throw parameterError(p, "No Retrofit annotation found.");
}

return result;
}

可以看出,内部调用了parseParameterAnnotation来解析参数注解,此外,还进行了相关判断,虽然参数中可以使用多个注解,但Retrofit强制用户只能使用一个,否则抛出异常。
parseParameterAnnotation中的源码实在太长了,这里就简单介绍下工作流程。首先根据注解来判断来校验使用上有没有错误,比如@Query注解必须在@Path和@Url后使用,使用了@Url注解那么请求方法注解中不允许设置请求路径等等;然后获取相应Converter用于转换类型(String,ResponseBody),最后初始化相应ParameterHandler返回。
ParameterHandler这个抽象类用于处理参数,还内置了不同类型的参数转换类,源码如下:

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
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, T value) throws IOException;

//Body注解类型的转换
static final class Body<T> extends ParameterHandler<T> {
private final Converter<T, RequestBody> converter;

Body(Converter<T, RequestBody> converter) {
this.converter = converter;
}

@Override void apply(RequestBuilder builder, T value) {
if (value == null) {
throw new IllegalArgumentException("Body parameter value must not be null.");
}
RequestBody body;
try {
body = converter.convert(value);//转换为RequestBody
} catch (IOException e) {
throw new RuntimeException("Unable to convert " + value + " to RequestBody", e);
}
builder.setBody(body);//设置Body
}
}
//..
//省略了其他注解类型转换代码
}

调用服务接口

以上介绍了retrofit.create(XX.class);用于创建服务方法接口的过程。现在该进行相关调用了。我们知道,创建服务方法会返回一个Call<XX>对象,通过Call<XX>可以进行相关异步同步调用。
默认CallAdapter相关源码实现在OkHttpCall中,源码如下:

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
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");

okhttp3.Call call;//okhttp中的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();//创建原始Call,即okhttp中的Call对象
} catch (Throwable t) {
failure = creationFailure = t;
}
}
}

if (failure != null) {
callback.onFailure(this, failure);
return;
}

if (canceled) {
call.cancel();
}

//通过enqueue进行异步调用
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);
}
}

从源码不难看出,首先通过createRawCall()来创建OkHttp中的Call对象,然后通过Call进行异步/同步调用,获取结果后通过parseResponse解析OkHttp中的Response,然后进行相应回调。
createRawCall()用于创建OkHttp中的Call对象,源码如下:

1
2
3
4
5
6
7
8
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);//通过 serviceMethod.toRequest进行转换成Request
okhttp3.Call call = serviceMethod.callFactory.newCall(request);//调用newCall返回Call对象,默认callFactory为OkHttpClient,OkHttpClient也实现了okhttp3.Call.Factory接口。
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}

parseResponse用于解析原始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
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();//获取ResponseBody

//移除响应体
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();

int code = rawResponse.code();//获取状态吗
//code < 200 || code >= 300
if (code < 200 || code >= 300) {
try {
//将整个rawBody缓冲到内存中回调
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
//code == 204 || code == 205
if (code == 204 || code == 205) {
//此时没有响应体,只需回调状态
return Response.success(null, rawResponse);
}

ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);//通过`serviceMethod.toResponse`转换为对应对象
//回调
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}

createRawCall()parseResponse的源码中,可以发现,通过 serviceMethod.toRequest进行转换成OkHttp中的Request,通过serviceMethod.toResponse将OkHttp中的Response转换为对应对象。
toRequest相关源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Request toRequest(Object... args) throws IOException {
// RequestBuilder
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);

//ParameterHandler数组
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

//...

for (int p = 0; p < argumentCount; p++) {
//遍历数组进行循环应用
handlers[p].apply(requestBuilder, args[p]);
}

return requestBuilder.build();//通过build()返回Request对象
}

toResponse源码非常简单,如下:

1
2
3
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}

默认情况下,会调用BuiltInConverters中的转换器来转换,当然,更多时候我们回去应用Gson转换器来进行转换。

最后

  • GsonConverterFactory是怎么工作的?
    一般情况下,我们会加入addConverterFactory(GsonConverterFactory.create())来增加Gson转换功能。

    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
       public final class GsonConverterFactory extends Converter.Factory {
    //默认Gson
    public static GsonConverterFactory create() {
    return create(new Gson());
    }
    //自己配置Gson
    public static GsonConverterFactory create(Gson gson) {
    return new GsonConverterFactory(gson);
    }

    private final Gson gson;

    private GsonConverterFactory(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    this.gson = gson;
    }

    //转换ResponseBody
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
    Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));//根据Type获取TypeAdapter
    return new GsonResponseBodyConverter<>(gson, adapter);//转换逻辑代码
    }

    //转换成RequestBody
    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
    Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));//根据Type获取TypeAdapter
    return new GsonRequestBodyConverter<>(gson, adapter);//转换逻辑代码
    }

    ResponseBody核心转换代码:

    1
    2
    3
    4
    5
    6
    7
    8
      @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());//创建JsonReader
    try {
    return adapter.read(jsonReader);//通过adapter转换
    } finally {
    value.close();//关闭流
    }
    }

    RequestBody核心转换代码:

    1
    2
    3
    4
    5
    6
    7
    @Override public RequestBody convert(T value) throws IOException {
    Buffer buffer = new Buffer();
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
    JsonWriter jsonWriter = gson.newJsonWriter(writer);//获取JsonWriter
    adapter.write(jsonWriter, value);//adapter将value转换为Gson
    jsonWriter.close();
    return Re
  • RxJavaCallAdapterFactory是怎么工作的?
    我们还可以加入addCallAdapterFactory(RxJavaCallAdapterFactory.create())使你的代码可以进行响应式编程。

    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
    //直接创建    
    public static RxJavaCallAdapterFactory create() {
    return new RxJavaCallAdapterFactory(null);
    }

    //指定工作线程创建
    public static RxJavaCallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJavaCallAdapterFactory(scheduler);
    }

    @Override
    public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    //..
    //省略了部分源码,
    //通过getCallAdapter来获取Adapter
    CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);

    return callAdapter;
    }

    //获取CallAdapter<Observable<?>>
    private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
    Class<?> rawObservableType = getRawType(observableType);
    //..
    //省略了部分源码,
    //一般会走SimpleCallAdapter
    return new SimpleCallAdapter(observableType, scheduler);
    }

    //SimpleCallAdapter的源码如下
    static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {
    private final Type responseType;
    private final Scheduler scheduler;

    SimpleCallAdapter(Type responseType, Scheduler scheduler) {
    this.responseType = responseType;
    this.scheduler = scheduler;
    }

    @Override public Type responseType() {
    return responseType;
    }

    @Override public <R> Observable<R> adapt(Call<R> call) {
    //通过Observable.create创建被观察者
    Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
    .lift(OperatorMapResponseToBodyOrError.<R>instance());
    if (scheduler != null) {
    return observable.subscribeOn(scheduler);//切换到指定线程
    }
    return observable;
    }
    }

    CallOnSubscribe中使用了RequestArbiter中包装了Call<T>对象,然后通过call.execute()同步执行,最后将结果subscriber.onNext(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
       static final class RequestArbiter<T> extends AtomicBoolean implements Subscription, Producer {
    private final Call<T> call;//原始的Call
    private final Subscriber<? super Response<T>> subscriber;

    RequestArbiter(Call<T> call, Subscriber<? super Response<T>> subscriber) {
    this.call = call;
    this.subscriber = subscriber;
    }

    @Override public void request(long n) {
    //...
    try {
    Response<T> response = call.execute();//call.execute()同步执行
    if (!subscriber.isUnsubscribed()) {
    subscriber.onNext(response);//onNext回调
    }
    } catch (Throwable t) {
    Exceptions.throwIfFatal(t);
    if (!subscriber.isUnsubscribed()) {
    subscriber.onError(t);
    }
    return;
    }

    if (!subscriber.isUnsubscribed()) {
    subscriber.onCompleted();
    }
    }

    @Override public void unsubscribe() {
    call.cancel();
    }

    @Override public boolean isUnsubscribed() {
    return call.isCanceled();
    }
    }

本篇解读到此结束。