Retrofit的使用

概述

Retrofit是Http网络请求框架,是基于Okhttp进行封转的库。能使我们的网络请求工作变得简洁高效。隐藏一切可以隐藏的细节。这也是所有第三方库的一个特点。在网上看到一段我非常认同的话:我们需要牢牢的记住:所有的第三方库能实现的功能,我们使用原生的API只要花时间和精力也能实现,但是可能会出现很多的bug而且会花费较多的时间和精力,而且性能也不一定很好,第三方的库会帮我们封装底层的一些代码,避免我们做重复多余易出错的事情,让我们专注于业务逻辑,所以学习任何一个第三方库都将是简单的,我们不应心生畏惧。
今天我们主要分析Retrofit2。

Retrofit的使用

Retrofit实例

1
2
3
4
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/") //设置Url地址
.addConverterFactory(GsonConverterFactory.create()) //设置Gson数据解析器
.build();

GitHubService service = retrofit.create(GitHubService.class);
假如get访问的地址是: http://localhost:8080/key=value
这里的baseUrl就是 http://localhost:8080/ ,而后面跟的就是参数。通常baseUrl必须以 /(斜线) 结束,不然会抛出一个IllegalArgumentException(针对于2.X版本)。

接口的定义

GET和POST可满足平时绝大多数的访问需求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface ImageService {
/**
*GET请求
*这里引入的注解意思是访问:http://localhost:8080?id=id,直接在BaseUrl后面添加参数id
*/
@GET("image/{id}")
Call<ResponseBody> getImage(@Path("id") int id);

/**
*POST请求
*可直接以对象的方式提交,对象包含了必要的参数
*/
@POST("users/new")
Call<User> createUser(@Body User user);
}

除此之外还有PUT,DELETE,PATCH,HEAD等,其中的参数体除了@Path和@Body之外,还有@Field,@FieldMap等用于文件的上传的场景。具体如下:

使用

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 void request() {

//步骤1:创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/") // 设置 网络请求 Url
.addConverterFactory(GsonConverterFactory.create()) // 数据转换,设置使用Gson解析
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava
.build();

// 步骤2:动态代理,创建 网络请求接口 的实例
GetRequest_Interface request = retrofit.create(ImageService.class);

//对 发送请求 进行封装
Call<Translation> call = request.getImage(123456);//对应接口中的方法

//步骤3:发送网络请求(异步)
call.enqueue(new Callback<T>() {
//请求成功时回调
@Override
public void onResponse(Call<T> call, Response<T> response) {
// 步骤7:处理返回的数据结果
response.body().show();
}

//请求失败时回调
@Override
public void onFailure(Call<T> call, Throwable throwable) {
System.out.println("连接失败");
}
});
}

这里的步骤2需要注意一下,传入一个接口的class,返回一个对象。这个对象就是我们的代理对象,我们可以查看一下Retrofit的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
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, 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 serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

可以看出InvocationHandler,返回代理对象。
如果不清楚代理设计模式的话可以点击【 代理设计模式 】。

总结

以上的使用方式可总结为:
首先构造retrofit,几个核心的参数呢,主要就是baseurl,callFactory(默认okhttpclient),converterFactories,adapterFactories。
然后通过create方法拿到接口的实现类,这里利用Java的Proxy类完成动态代理的相关代理
在invoke方法内部,拿到我们所声明的注解以及实参等,构造ServiceMethod,ServiceMethod中解析了大量的信息,最后可以通过toRequest构造出okhttp3.Request对象。有了okhttp3.Request4. 对象就可以很自然的构建出okhttp3.call,最后calladapter对Call进行装饰返回。
拿到Call就可以执行enqueue或者execute方法了。