Retrofit 源码深度解析-(1)序言

1.1 简介

Retrofit是一个类型安全的Android和Java HTTP客户端,内部基于OkHttp,以一种优雅的方式(接口的形式)提供给用户以发起HTTP请求。


1.2 使用方式

Retrofit的使用方式比较简单,定义HTTP的java接口,构建一个Retrofit对象,使用Retrofit实例创建接口实例,进行调用。

@Test
public void test() throws IOException {
  // 创建Build
  Retrofit.Builder builder = new Retrofit.Builder();
	
  // 添加build信息
  builder.client(new OkHttpClient());
  builder.baseUrl("https://www.baidu.com/");
  // 传入CallAdapterFactory
  builder.addCallAdapterFactory(new DefaultCallAdapt.DefaultCallAdaptFactory());
  // 传入ConverterFactory
  builder.addConverterFactory(new MyConverterFactory());
  
  // 实例化Retrofit对象
  Retrofit retrofit = builder.build();

  // 构建接口实例并调用
  Response stringResponse = retrofit.create(BaiduApi.class).get1("").execute();
	
  // 输出结果
  System.out.println(JSON.toJSON(stringResponse));
}

可以看到,Retrofit的使用方式很优雅,免去了请求参数、响应参数的转化等繁琐操作。

下面就主要几个关键参数先简单说明一下:

  • client

该方法的签名信息为Builder client(okhttp3.OkHttpClient client)

可以看到,需要传入一个OkHttpClient实例,这个方法是用来给使用者进行扩展的,在构建OkHttpClient时,可以自定义自己的插件、连接池等等信息

  • baseUrl

顾名思义,定义baseUrl。

所以在定义Service接口时,只需要定义具体的path即可

  • CallAdapterFactory

这个工厂是用来构建CallAdapter的,CallAdapter用来干嘛下面会详细讲到

  • ConverterFactory

这个工厂是用来构建Converter的,Converter的定义是将返回结果进行转换成业务需要的对象,下面会详细描述。

其中 CallAdapterFactoryConverterFactory的代码如下

public class DefaultCallAdapt<R> implements CallAdapter<R, Call<R>> {
    Type returnType;

    public DefaultCallAdapt(Type returnType) {
        this.returnType = returnType;
    }

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

    @Override
    public Call<R> adapt(Call<R> call) {
        // 这个适配器不做啥操作,直接返回
        return call;
    }

    public static class DefaultCallAdaptFactory extends Factory {

        @Override
        public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
          	// 获取第0个定义的参数类型
            final Type responseType =getParameterUpperBound(0, (ParameterizedType) returnType);
            return new DefaultCallAdapt(responseType);
        }
				
         public static Type getParameterUpperBound(int index, ParameterizedType type) {
            Type[] types = type.getActualTypeArguments();
            if (index < 0 || index >= types.length) {
                throw new IllegalArgumentException(
                        "Index " + index + " not in range [0," + types.length + ") for " + type);
            }
            Type paramType = types[index];
            if (paramType instanceof WildcardType) {
                return ((WildcardType) paramType).getUpperBounds()[0];
            }
            return paramType;
        }

        public static Class<?> getRawType(Type type) {
            return Factory.getRawType(type);
        }
    }
}
static class MyConverterFactory extends Converter.Factory {
        @Override
        public Converter<ResponseBody, ?> responseBodyConverter(
                Type type, Annotation[] annotations, Retrofit retrofit) {
            return new ToStringConverterFactory().responseBodyConverter(type, annotations, retrofit);
        }
}

static class ToStringConverterFactory extends Converter.Factory {
        static final MediaType MEDIA_TYPE = MediaType.get("text/plain");

        @Override
        public Converter<ResponseBody, String> responseBodyConverter(
                Type type, Annotation[] annotations, Retrofit retrofit) {
            if (String.class.equals(type)) {
          			// 简单的返回string
                return ResponseBody::string;
            }
            return null;
        }

        @Override
        public Converter<String, RequestBody> requestBodyConverter(
                Type type,
                Annotation[] parameterAnnotations,
                Annotation[] methodAnnotations,
                Retrofit retrofit) {
            if (String.class.equals(type)) {
                return value -> RequestBody.create(MEDIA_TYPE, value);
            }
            return null;
        }
}
public interface BaiduApi {

    @GET("/")
    Call<String> get1(@Query("aaa") String args);

    @GET("/")
    Response<String> get2(@Query("aaa") String args);

}

由上面的例子看到,使用Retrofit的典型步骤分为三步:

  1. 使用配置信息构建Retrofit实例
  2. 使用Retrofit实例,构建Service实例
  3. 调用Service实例方法,发起请求

接下来,根据这三个步骤,深入剖析Retrofit的源码以及其精髓所在。

Retrofit 源码深度解析-(2)初始化

posted @ 2021-09-14 14:39  卡卡一点都不卡  阅读(37)  评论(0编辑  收藏  举报