Retrofit使用
1、添加依赖
在Maven中使用:
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.9.0</version>
</dependency>
在Gradle中使用:
// retrofit2依赖
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// Gson依赖
implementation "com.squareup.retrofit2:converter-gson:2.5.0"
implementation "com.google.code.gson:gson:2.8.6"
// 日志拦截器
implementation 'com.squareup.okhttp3:logging-interceptor:3.3.1'
注意:版本号可能会不一样,具体到官网进行查找
2、创建请求接口
将所有的接口方法都写在这里面
因为Retrofit是通过Interface来管理HTTP API,而且这个接口不能继承其他接口
public interface RemoteService {
/**
* 网络请求一个注册接口
*
* @param model RegisterModel
* @return RspModel<AccountRspModel>
*/
@POST("account/register")
Call<RspModel<AccountRspModel>> accountRegister(@Body RegisterModel model);
}
3、网络请求的封装
在项目中,为了避免代码冗余,我们经常会将网络请求进行一个整体的封装,以单例模式
/**
* 网络请求的封装
*
* @author : iwen大大怪
* @create : 12-7 007 18:19
*/
public class Network {
// 单例模式
private static Network instance;
private OkHttpClient client;
private Retrofit retrofit;
static {
instance = new Network();
}
private Network() {
}
/**
* 步骤1:构建一个Retrofit
*/
public static Retrofit getRetrofit() {
if (instance.retrofit != null){
return instance.retrofit;
}
// 步骤:2:得到一个OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
// 跳过ssh检查
.sslSocketFactory(OkHttpSSH.createSSLSocketFactory(), new OkHttpSSH.TrustAllCerts())
.connectTimeout(10, TimeUnit.SECONDS)// 设置超时时间
.writeTimeout(10, TimeUnit.SECONDS)// 设置写入超时时间
.readTimeout(20, TimeUnit.SECONDS)// 设置读取超时时间
// 给所有的请求添加一个拦截器(看具体需求)
//.addInterceptor()
.build();
// 步骤3:获取Retrofit对象
Retrofit.Builder builder = new Retrofit.Builder();
instance.retrofit = builder
.baseUrl("根据需要填写")
.client(client) // 设置client
.addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
.build();
return instance.retrofit;
}
/**
* 步骤4:返回一个请求代理
* @return RemoteService
*/
public static RemoteService mRemoteService(){
// 传入具体接口类,将其转换成动态代理
return Network.getRetrofit().create(RemoteService.class);
}
}
4、使用
RemoteService service = Network.mRemoteService();
// 调用具体接口请求的方法
Call<RspModel<LogoutRspModel>> call = service.accountRegister(model);
// 发起异步请求
call.enqueue(new Callback<RspModel<LogoutRspModel>>() {
@Override
public void onResponse(Call<RspModel<LogoutRspModel>> call, Response<RspModel<LogoutRspModel>> response) {
// 请求成功回调
}
@Override
public void onFailure(Call<RspModel<LogoutRspModel>> call, Throwable t) {
// 请求失败回调
}
});
Retrofit架构解析
1、Okhttp的缺陷
- **问题一:**用户网络请求接口配置繁琐,尤其是需要配置复杂的请求Body、请求头、参数的时候。
- **问题二:**数据解析过程需要用户手动拿到responsbody进行解析,不能复用。
- **问题三:**无法适配自动进行线程切换。
- **问题四:**一旦存在嵌套网络请求,就会陷入“回调陷阱”。
2、Retrofit是什么?
准确来说,Retrofit是一个RESTful的HTTP网络请求框架的封装。
**原因:**网络请求的工作本质还是由OKHTTP完成,而Retrofit只是负责网络请求接口的封装。
3、Retrofit设计的任务
tempimg-1302248544.cos.ap-chengdu.myqcloud.com/Img/PingMu/…
请求前:
统一的配置网络请求头:使用建造者模式、门面模式来对一些参数进行统一的配置,并且将其保存。
一致适配请求request:create()方法里面使用了动态代理模式,这样子就可以代理所有类对象。
请求后:
线程切换:
数据适配:
4、Retrofit封装的点
- Build 模式创建网络请求的基本配置。(解决了问题一)
- 用注解来排列组合合成网络请求,以不变应万变。(解决了问题一)
- 统一提供Gson解析,提供可复用,易拓展的数据解析方案。(解决了问题二)
- 自定义Executor(Handler)完成线程的切换。(解决了问题三)
Retrofit这个类就是保存一系列的参数给后面使用,使用的是Build模式
5、Retrofit设计模式
在构建Retrofit时,采用的是建造者模式、外观模式
在适配一致请求request时:Create()方法里面使用了动态代理模式
静态代理模式:
- 代理类和委托类有同样的接口。
- 代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后的消息处理等。
- 一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正的实现服务,而是通过调用委托类的对象的相关方法,来提供服务。
动态代理模式:
代理类在程序运行前不存在、运行时由程序动态生成的代理方式称为动态代理。
传进去我们接口的类对象即可生成对应的实例并调用
具体方法
,是因为这里面实际上retrofit利用动态代理模式生成了一个代理对象(并且实现了RemoteService),然后一旦调用了RemoteService的方法,就会触发代理对象的invoke方法,从而在invoke总拦截并获得了RemoteService的所有方法以及对应的那些@GET
@POST
等Retrofit的注解信息,然后利用OKhttp完成真正的请求操作。
create(RemoteService.class);
这一行的时候,虚拟机内部生成了代理类的Class二进制流,并且加载到虚拟机中形成代理类的Class对象,再反射得到代理类对象,而该代理类即实现了GitHubService,并且持有了InvocationHandler的引用。
我们从Retrofit
的create
方法一探究竟:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 通过Proxy.newProxyInstance生成了代理类
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);
}
});
}
可以看到,也是通过Proxy.newProxyInstance
生成了代理类,并new了一个匿名内部InvocationHandler
对象,重写它的invoke
方法,相当于通过我们传进来的接口,生成了一个接口的代理类,并且实现了接口是所有方法(因为InvocationHandler
的参数里传进去了new Class<?>[] { service }
),然后返回给外部。
外部一旦调用了接口方法,例如request.getData();
,就会触发InvocationHandler
的invoke
,从而根据注解生成Retrofit的ServiceMethod
和OkHttpCall
对象,这些都是发起网络请求的必备信息,然后最终发起请求。