Retrofit入门

1,343 阅读5分钟

Retrofit使用

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的缺陷

  1. **问题一:**用户网络请求接口配置繁琐,尤其是需要配置复杂的请求Body、请求头、参数的时候。
  2. **问题二:**数据解析过程需要用户手动拿到responsbody进行解析,不能复用。
  3. **问题三:**无法适配自动进行线程切换。
  4. **问题四:**一旦存在嵌套网络请求,就会陷入“回调陷阱”。

2、Retrofit是什么?

准确来说,Retrofit是一个RESTful的HTTP网络请求框架的封装。

**原因:**网络请求的工作本质还是由OKHTTP完成,而Retrofit只是负责网络请求接口的封装。

3、Retrofit设计的任务

tempimg-1302248544.cos.ap-chengdu.myqcloud.com/Img/PingMu/…

请求前:

  1. 统一的配置网络请求头:使用建造者模式、门面模式来对一些参数进行统一的配置,并且将其保存。

  2. 一致适配请求request:create()方法里面使用了动态代理模式,这样子就可以代理所有类对象。

请求后:

  1. 线程切换:

  2. 数据适配:

4、Retrofit封装的点

  1. Build 模式创建网络请求的基本配置。(解决了问题一)
  2. 用注解来排列组合合成网络请求,以不变应万变。(解决了问题一)
  3. 统一提供Gson解析,提供可复用,易拓展的数据解析方案。(解决了问题二)
  4. 自定义Executor(Handler)完成线程的切换。(解决了问题三)

Retrofit这个类就是保存一系列的参数给后面使用,使用的是Build模式

5、Retrofit设计模式

在构建Retrofit时,采用的是建造者模式、外观模式

在适配一致请求request时:Create()方法里面使用了动态代理模式

静态代理模式:

  • 代理类和委托类有同样的接口。
  • 代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后的消息处理等。
  • 一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正的实现服务,而是通过调用委托类的对象的相关方法,来提供服务。

动态代理模式:

代理类在程序运行前不存在、运行时由程序动态生成的代理方式称为动态代理。

传进去我们接口的类对象即可生成对应的实例并调用具体方法,是因为这里面实际上retrofit利用动态代理模式生成了一个代理对象(并且实现了RemoteService),然后一旦调用了RemoteService的方法,就会触发代理对象的invoke方法,从而在invoke总拦截并获得了RemoteService的所有方法以及对应的那些@GET @POST 等Retrofit的注解信息,然后利用OKhttp完成真正的请求操作。

juejin.cn/post/684490…

create(RemoteService.class);

这一行的时候,虚拟机内部生成了代理类的Class二进制流,并且加载到虚拟机中形成代理类的Class对象,再反射得到代理类对象,而该代理类即实现了GitHubService,并且持有了InvocationHandler的引用。

我们从Retrofitcreate方法一探究竟:

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();,就会触发InvocationHandlerinvoke,从而根据注解生成Retrofit的ServiceMethodOkHttpCall对象,这些都是发起网络请求的必备信息,然后最终发起请求。