Retrofit 简介
A type-safe HTTP client for Android and Java
Retrofit是Square公司开发的一款针对Java和Android平台开发的网络请求框架,目前的Retrofit2底层是基于OkHttp。Retrofit + OkHttp基本成为目前App开发网络请求的标配了。
Retrofit 使用
加入Retrofit的依赖
1 | # Retrofit 自身的依赖 |
ProGuard 配置
1 | # Platform calls Class.forName on types which do not exist on Android to determine platform. |
创建接口
以下以访问Gank的API接口为例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public interface GankApi {
/**
*
* 分类数据: http://gank.io/api/data/数据类型/请求个数/第几页
* 数据类型: 福利 | Android | iOS | 休息视频 | 拓展资源 | 前端 | all
* 请求个数: 数字,大于0
* 第几页:数字,大于0
*/
"day/{year}/{month}/{day}") (
Observable<DailyEntity> getDailyData(@Path("year")int year, @Path("month")int month, @Path("day")int day);
"data/{type}/{pageSize}/{page}") (
Observable<HttpResult<List<GankEntity>>> getGankData("type") String type, ("pageSize") int PageSize, ("page") int page); (
}
Retrofit 提供了很多注解,比如GET, POST, DELETE 代表请求的类型,@Path,用来组装URL path等
实例化Retrofit对象
1 | public class GankService { |
小结
Retrofit 通过接口代理的方式,将设置在接口上的参数(请求类型,请求URL,请求参数,返回类型)等进行组织成一个完整的Request 然后交给OkHttp框架发送请求,OkHttp获取结果后交给Retrofit的Converter转换成期望的对象。综上所述,Retrofit可以理解为一个API请求的 ‘皮包工厂’。
Retrofit源码分析
以下基于Retrofit 2.0.2进行分析, Retrofit 整个源码非常简洁,总共37个类文件, 22个是注解类,其他类才15个还包括Util类。
Retofit成员变量分析
1 | // 用作缓存解析Annotation数据用的,也就是说如何annotiation被解析了会缓存起来,毕竟通过反射是很消耗性能的 |
Retrofit 核心代码
Retrofit通过动态代理生产代理类,在此过程中去解析注解,封装请求,发送请求,解析请求结果等操作。
所谓动态代理,是在程序Runtime时,通过反射机制在目标方法的前后加上一定的逻辑的过程。
动态代理分JDK的动态代理和CGLib动态代理。
Retrofit 正是使用了JDK的动态代理。
1 | public <T> T create(final Class<T> service) { |
获取Platform
它是通过是否存在特定的文件,来推断出对应的平台,只不过这里面有iOS平台,难道iOS平台也可以使用?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20private 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) {
}
try {
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
解析注解
loadServiceMethod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/**
* 1. 首先从serviceMethodCache中获取ServiceMethod
* 2. 解析Annotation成ServiceMethod对象
* 3. 再将ServiceMethod放入serviceMethodCache,做cache用
*
*/
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 重点在这里,同样是使用采用Builder模式,直接看build方法
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}build方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public ServiceMethod build() {
// 获取callAdapter,Android对应的是ExecutorCallAdapterFactory
callAdapter = createCallAdapter();
// 获取返回类型数据
responseType = callAdapter.responseType();
// 创建转换器对象
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
// 解析添加在在method的注解
parseMethodAnnotation(annotation);
}
...
return new ServiceMethod<>(this);
}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
41private 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.");
}
// 解析header
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;
}
}
如何在Retrofit中使用RxJava
由于Retrofit设计的扩展性非常强,你只需要添加一个CallAdapter就可以了
1 | Retrofit retrofit = new Retrofit.Builder() |
上面代码创建了一个Retrofit对象,支持Proto和Gson两种数据格式,并且还支持RxJava
更多可以参考RxJava 与 Retrofit 结合的最佳实践
总结
Retrofit就是在组装请求,把请求交给Adapter(OkHttp)去处理请求,然后拿回结果用Converter将原始数据转化成期望的对象。 通过Retrofit的封装,使得App网络请求层代码简洁,方便维护。