IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Retrofit2 源码解读

    summer发表于 2016-07-18 08:36:25
    love 0

    转载请注明本文出自maplejaw的博客(http://blog.csdn.net/maplejaw_)

    开源库地址:https://github.com/square/retrofit
    解读版本:2.1.0

    基本概念

    Retrofit 是一个针对Java/Android类型安全的Http请求客户端。
    基本使用如下:

    1. 首先定义一个接口,抽象方法的返回值必须为Call<XX>。

      public interface GitHubService {
      @GET("users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);//默认CallAdapter返回值必须为`Call<XX>`。
      }

    2. 通过Retrofit的create创建接口实现

      //初始化Retrofit
      Retrofit retrofit = new Retrofit.Builder()
      .baseUrl("https://api.github.com/") //必须以斜杠结尾
      .addConverterFactory(GsonConverterFactory.create())//添加Gson转换工厂
      .build();

      //通过Retrofit创建接口实现
      GitHubService service = retrofit.create(GitHubService.class);

    3. 接口调用相关方法获取Call<XX>,然后就能和Okhttp一样进行同步/异步调用。

      Call<List<Repo>> repos = service.listRepos("octocat");
      //异步调用
      repos.enqueue(new Callback<List<Repo>>() {
      @Override
      public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
      List<String> list=response.body();//调用body()
      }

      @Override
      public void onFailure(Call<List<Repo>> call, Throwable t) {

      }
      });
      //同步调用
      Response<List<Repo>> response=repos.execute();

    源码解读

    Retrofit中的相关注解

    请求方法注解

    该类注解用于指明请求方法,在使用时必须指定且只可指定一种请求方法。

    1. @GET
      用来指明请求方法和相对/绝对/完整路径。当然也可以配合@Url使用。

      public interface RequestService {
      @GET("xx/xxx") //指定相对路径
      Call<ResponseBody> getContent1();

      @GET("/xxx") //指定绝对路径,相对路径和绝对路径的区别见后文
      Call<ResponseBody> getContent1();

      @GET("http://www.baidu.com") //指定完整Url
      Call<ResponseBody> getContent2();

      @GET //配合@Url使用,此时@GET只能指明请求方法,路径参数必须留空
      Call<ResponseBody> getContent3(@Url String url);
      }

    2. @POST
      用来指明请求方法和相对/绝对/完整路径,同时也可以配合@Url使用。

      public interface RequestService {
      @POST("xx/xxx") //指定相对路径
      Call<ResponseBody> getContent1();
      @POST("/xxx") //指定绝对路径
      Call<ResponseBody> getContent1();
      @POST("http://www.baidu.com") //指定完整Url
      Call<ResponseBody> getContent2();

      @POST //配合@Url使用,此时@POST只能指明请求方法,路径参数必须留空
      Call<ResponseBody> getContent3(@Url String url);
      }

    3. @DELETE,@HEAD,@OPTIONS,@PATCH,@PUT
      这几种请求方法和POST/GET在使用上没有太大区别,由于不太常用,这里就不做介绍。

    请求参数注解

    1. @Path
      该注解用于替换Url的路径(path)部分。

      public interface RequestService {
      @GET("/image/{id}") //替换{}内的路径
      Call<ResponseBody> getImage(@Path("id") int id);

      @GET("/user/{name}") //替换{}内的路径
      Call<ResponseBody> getUserInfo(@Path("name") String name);

      @GET("/user/{name}") //替换{}内的路径,encoded=true则表示自己处理编码,
      Call<ResponseBody> getUserInfo(@Path(value="name", encoded=true) String name);

      }

      上述代码有一个是否需要编码的问题,这里举个例子:假如输入名字maple+jaw,默认情况下为GET中的注解为/user/maple%2Bjaw,如果指明自己处理编码,此时输入maple+jaw,路径参数为/user/maple+jaw

    2. @Query
      该注解用于在Url后追加查询参数

      public interface RequestService {
      @GET("/list") //追加查询参数后,此时路径为/list?page=xx
      Call<ResponseBody> getList(@Query("page") int page);

      @GET("/list") //追加查询参数后,此时路径为/list?page=xx&category=xx
      Call<ResponseBody> getList(@Query("page") int page,@Query("category") String category);

      @GET("/list") //同理也可指定是否编码
      Call<ResponseBody> getList(@Query(value="category",encoded=true) String category);

      }

    3. @QueryMap
      @QueryMap和@Query的作用是一样的,只不过@QueryMap是以map的形式追加参数,可以一次性追加多个参数

      public interface RequestService {
      @GET("/search")
      Call<ResponseBody> getList(@QueryMap Map<String, String> filters);

      }

    4. @Field
      该注解用于添加表单数据,须配合@FormUrlEncoded一起使用。

      public interface RequestService {
      @FormUrlEncoded
      @POST("/register") //使用@Field提交表单数据
      Call<ResponseBody> register(@Field("name") String name,@Field("password") String pwd,);

      @FormUrlEncoded
      @POST("/register") //使用@Field提交表单数据,encoded=true表示该数据自己编码
      Call<ResponseBody> register(@Field(value="name",encoded=true) String name,@Field("password") String pwd,);

      }

    5. @FieldMap
      @Field和@FieldMap的作用一样,后者以map的方式提交表单数据

      public interface RequestService {
      @FormUrlEncoded
      @POST("/register") //使用@FieldMap提交表单数据
      Call<ResponseBody> register(@FieldMap Map<String, String> fields);

      }

    6. @Header
      该注解用于指明请求头参数,相同名字的请求头是惟一的,新的会直接覆盖旧的。

      public interface RequestService {
      @GET("/")
      Call<ResponseBody> getContent(@Header("Accept-Language") String lang
      ,@Header("Cache-Control") String cache);

      }

    7. @Headers
      该注解用于指明请求头参数,和@Header的区别在于不会覆盖掉相同名字的请求参数

      public interface RequestService {
      @Headers("Cache-Control: max-age=640000")
      @GET("/")
      Call<ResponseBody> getContent();

      @Headers({"Cache-Control: max-age=640000","Accept-Language: gzip, deflate"})
      @GET("/")
      Call<ResponseBody> getContent();

      }

    8. @HeaderMap
      @HeaderMap和@Headers的作用一样,区别在于以Map的形式指明请求头参数。

      public interface RequestService {
      @GET("/search")
      Call<ResponseBody> getList(@HeaderMap Map<String, String> headers);

      }

    9. @Part
      该注解用于定义分块表单请求中的块。需配合@Multipart一起使用。
      如果类型是MultipartBody.Part,内容将直接被使用。(@Part MultipartBody.Part part)
      如果类型是RequestBody,将会和它的contentType一起使用。(@Part("foo") RequestBody foo)
      其他类型将会通过转换器转换后使用。(@Part("foo") Image photo)
      @Part(XX),XX表示表单名。

      public interface RequestService {
      @Multipart
      @POST("/")
      Call<ResponseBody> example(@Part("description") String description,
      @Part(value = "image", encoding = "8-bit") RequestBody image);

      }

    10. @PartMap
      和@Part的作用一样,区别在于以Map的形式定义,其中Map的Value类型转换同@Part。

      public interface RequestService {
      @Multipart
      @POST("/upload")
      Call<ResponseBody> example(@Part("file\"; filename=\"test.txt") RequestBody file,
      @PartMap Map<String, RequestBody> params);

      }

    11. @Body
      当请求体不是表单/分块类型时,该注解用于直接指定请求体。请求体内部转换时通过Converter转换为RequestBody实现的。

      public interface RequestService {
      @POST("/upload")
      Call<ResponseBody> example(@Body String conent);

      }

    12. @HTTP
      该注解用于自定义请求。

      interface Service {
      @HTTP(method = "DELETE", path = "remove/", hasBody = true)
      Call<ResponseBody> deleteObject(@Body RequestBody object);

      @HTTP(method = "CUSTOM", path = "custom/endpoint/")
      Call<ResponseBody> customEndpoint();
      }

    13. @Streaming
      使用该注解后,将不会缓冲流到内存中,只在返回类型为Call<ResponseBody>时起效。如果使用Retrofit下载大文件,务必要加上该注解。

    Retrofit构造

    按照老规矩,从Retrofit的构造方法下手,要想了解Retrofit的构造方法,必须先了解以下几个类

    Call接口

    注意,此Call非Okhttp中的Call,结构如下,通过Call可以进行同步和异步请求,还能判断取消与否。
    image_1ank3mstmho91qum9k646415a29.png-20.2kB

    CallAdapter

    CallAdapter主要用来代理call(默认为OkhttpCall)以方便实现自己想要的功能,比如RxJavaCallAdapter等。可以通过Retrofit.Builder#addCallAdapterFactory(Factory)来添加CallAdapterFactory。

    public interface CallAdapter<T> {

    //返回响应类型,即Call<Repo>的响应类型为Repo
    Type responseType();

    //返回一个代理call的实例。
    <R> T adapt(Call<R> call);
    //..
    //省略了工厂源码,用于获取CallAdapter的实例
    }

    Callback

    Callback用于回调结果。

    public interface Callback<T> {

    //接收HTTP响应(404,500也会调用,所以需要调用isSuccessful来判断)
    void onResponse(Call<T> call, Response<T> response);

    //网络异常或者发生异常时调用
    void onFailure(Call<T> call, Throwable t);
    }

    Converter

    用于类型转换,使用Retrofit.Builder#addConverterFactory(Factory)添加转换工厂,比如添加Gson转换。

    public interface Converter<F, T> {
    T convert(F value) throws IOException;
    //..
    //省略了工厂源码
    }

    构造方法

    Retrofit构造方法采用构建者模式构造,源码如下。

    private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();//key为接口中定义方法,value为转换过后的方法

    public static final class Builder {
    private Platform platform;//平台:安卓、java等
    private okhttp3.Call.Factory callFactory; //okhttp的Call工厂类,自定义newCall将Request转为Call
    private HttpUrl baseUrl;//okhttp中的类,保存解析过的url
    private List<Converter.Factory> converterFactories = new ArrayList<>();//类型转换工厂列表。
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();//CallAdapter工厂列表。
    private Executor callbackExecutor;//回调线程池
    private boolean validateEagerly;//急需验证?作用在于直接将所有方法加入前面的map缓存中。

    Builder(Platform platform) {
    this.platform = platform;
    converterFactories.add(new BuiltInConverters());//添加默认的转换器
    }

    public Builder() {
    this(Platform.get());//通过Platform.get()获取关于当前平台的实现
    }

    public Retrofit build() {
    if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
    }

    okhttp3.Call.Factory callFactory = this.callFactory;
    if (callFactory == null) {
    callFactory = new OkHttpClient();//默认使用OkHttpClient
    }

    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {//默认使用平台默认回调线程池
    callbackExecutor = platform.defaultCallbackExecutor();
    }

    //将平台默认CallAdapter.Factory加入列表中
    List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
    adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

    //将默认Converter.Factory加入列表中
    List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

    return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
    callbackExecutor, validateEagerly);
    }

    可以看出,首选通过Platform.get()来获取平台实现然后添加了默认转换工厂。由于我们是Android平台,毋容置疑,接下来就去看看Andoird类的源码。
    image_1ank6t5fdqe51k5jm221ff116jjm.png-56.6kB

    static class Android extends Platform {
    //回调线程池
    @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();//主线程
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    //ExecutorCallAdapterFactory继承CallAdapter.Factory,内部代理了原来的Call<T>,用于将Callback回调到指定线程中。
    return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());

    @Override public void execute(Runnable r) {
    handler.post(r);//采用Hanlder#post回调到主线程
    }
    }
    }

    Andoird类的源码主要实现了两个方法,一个是实现了默认的回调线程池,用于在主线程中执行任务,另一个是实现了CallAdapter工厂,通过代理的方式,将执行结果回调到callbackExecutor中去执行。所以,我们只需将callbackExecutor赋值为MainThreadExecutor即可实现主线程间的回调。

    BuiltInConverters继承于Converter.Factory,Converter.Factory中有三个方法:

    • public Converter<ResponseBody, ?> responseBodyConverter(xx)用于将ResponseBody转换为指定类型,通常用于对响应结果的类型转换。
    • public Converter<?, RequestBody> requestBodyConverter(xx)用于将指定类型转为RequestBody。一般用于将@Body,@Part,@PartMap转为RequestBody
    • public Converter<?, String> stringConverter用于将指定类型转为String,用于将@Field,@FieldMap,@Path,@Query,@Header等注解的参数类型转为String。

    BuiltInConverters源码实现如下:

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
    Retrofit retrofit) {
    //根据类型进行选择不同的转换器
    if (type == ResponseBody.class) {//转换类型为ResponseBody
    if (Utils.isAnnotationPresent(annotations, Streaming.class)) {
    return StreamingResponseBodyConverter.INSTANCE;//如果使用了Steaming注解,就不缓冲到内存,直接返回OkHttp的ResponseBody。
    }
    return BufferingResponseBodyConverter.INSTANCE;//缓冲ResponseBody到内存后返回
    }
    if (type == Void.class) {
    return VoidResponseBodyConverter.INSTANCE;//Void就直接关闭ResponseBody
    }
    return null;
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
    Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {//默认只处理RequestBody相关类型
    return RequestBodyConverter.INSTANCE;
    }
    return null;
    }

    @Override public Converter<?, String> stringConverter(Type type, Annotation[] annotations,
    Retrofit retrofit) {
    if (type == String.class) {//默认只处理String类型的转换,说白了就是直接返回
    return StringConverter.INSTANCE;
    }
    return null;
    }
    //..
    //省略了部分源码
    }

    BuiltInConverters源码中最重要的在于responseBodyConverter方法,如果转换类型是ResponseBody且有@Streaming注解,那么将不会缓冲到内存。你可能会疑问两者有什么区别?那么我们想象一种情景——下载大文件。如果下载大文件时将ResponseBody缓冲到内存,OOM那是分分钟的事。

    Retrofit提供的用于自定义的方法如下:
    image_1ank9trh8mavpd16n1l85nm513.png-27.5kB

    • client(OkHttpClient) 用于自定义客户端
    • callFactory(okhttp3.Call.Factory factory)用于自定义Call工厂,重写newCall将Request转为Call。OkHttpClient就是实现了这个接口。
    • addConverterFactory添加类型转换工厂(Gson转换等)
    • addCallAdapterFactory添加CallAdapter代理工厂,用来代理原始的Call(RxJavaCallAdapter等)。
    • callbackExecutor自定义回调线程池,默认为主线程
    • validateEagerly是否继续验证,是就提前将所有方法转为ServiceMethod放入缓存中,而不是调用一个缓存一个
    • baseUrl用于定义基本链接,必须以”/”结尾

    假如基本地址为http://example.com/api/,关于baseUrl与注解中路径的拼接问题如下:

    注解中的路径 最终Url (baseUrl为http://example.com/api/)
    foo/bar/ http://example.com/api/foo/bar/
    /foo/bar/ http://example.com/foo/bar/
    https://github.com/square/retrofit/ https://github.com/square/retrofit/
    //github.com/square/retrofit/ http://github.com/square/retrofit/

    创建Service接口

    介绍完构造方法后,我们再来看看retrofit.create(XX.class);这个方法。

    public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);//验证接口,接口不能有继承
    if (validateEagerly) {
    eagerlyValidateMethods(service);//将所有方法(跳过默认方法)转为ServiceMethod放入map中
    }
    //使用代理
    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 (method.getDeclaringClass() == Object.class) {
    return method.invoke(this, args);
    }
    //JAVA8接口可以定义默认方法
    if (platform.isDefaultMethod(method)) {
    return platform.invokeDefaultMethod(method, service, proxy, args);
    }

    //直接看这里
    //将普通的Method转为ServiceMethod
    ServiceMethod serviceMethod = loadServiceMethod(method);
    //将ServiceMethod以及传入的参数值传入OkHttpCall。
    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
    //利用callAdapter代理OkHttpCall,默认直接返回。
    return serviceMethod.callAdapter.adapt(okHttpCall);
    }
    });
    }

    retrofit.create(XX.class);方法中使用了Java代理,核心在于,首先将普通的Method转为ServiceMethod,然后将ServiceMethod以及传入的参数值传入到OkHttpCall中,最终通过代理OkHttpCall来返回代理Call,默认是直接返回。

    ServiceMethod的创建

    接下来,我们来看看是怎样将Method转为ServiceMethod的,源码在loadServiceMethod方法中:

    ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);//首先从map中取看看是否已经缓存过
    if (result == null) {//否则构造ServiceMethod。
    result = new ServiceMethod.Builder(this, method).build();
    serviceMethodCache.put(method, result);//缓存map中
    }
    }
    return result;
    }

    loadServiceMethod的方法很简陋,直接传入了Method然后build(),那么这个build()又做了什么?

    public Builder(Retrofit retrofit, Method method) {
    this.retrofit = retrofit;
    this.method = method;
    this.methodAnnotations = method.getAnnotations();//赋值方法注解数组
    this.parameterTypes = method.getGenericParameterTypes();//赋值参数类型数组
    this.parameterAnnotationsArray = method.getParameterAnnotations();//赋值参数注解数组
    }

    public ServiceMethod build() {
    callAdapter = createCallAdapter();//创建CallAdapter,用来代理Call
    responseType = callAdapter.responseType();//获取返回类型
    //...
    responseConverter = createResponseConverter();//创建ResponseConverter,用来转换ResponseBody为指定类型

    for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);//遍历解析方法注解
    }
    //...
    int parameterCount = parameterAnnotationsArray.length;//parameterAnnotationsArray为参数注解数组
    parameterHandlers = new ParameterHandler<?>[parameterCount];//初始化ParameterHandler,用来处理参数相关
    for (int p = 0; p < parameterCount; p++) {//遍历参数注解数组
    Type parameterType = parameterTypes[p];//获取参数类型
    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];//获取参数注解数组
    //...
    //通过注解和参数类型,解析并赋值到parameterHandlers中
    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
    }

    //...

    return new ServiceMethod<>(this);
    }

    createCallAdapter用于创建CallAdapter。最终的源码在Retrofit类中,从源码可以看出,进行遍历源码,如果查询到就返回。

    public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
    Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
    //遍历Adapter集合,查到就返回
    CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
    return adapter;
    }
    }
    //..
    //省略了部分源码
    }

    同理,createResponseConverter也是。

    public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
    Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
    //遍历调用查询
    Converter<ResponseBody, ?> converter =
    converterFactories.get(i).responseBodyConverter(type, annotations, this);
    if (converter != null) {
    return (Converter<ResponseBody, T>) converter;
    }
    }

    //..
    //省略了部分源码
    }

    parseMethodAnnotation用于遍历解析方法上的注解,比如请求方法,请求头之类的。

    private 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 = (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.");
    }
    headers = parseHeaders(headersToParse);//解析Header
    } else if (annotation instanceof Multipart) {
    //Multipart
    if (isFormEncoded) {
    throw methodError("Only one encoding annotation is allowed.");
    }
    isMultipart = true;
    } else if (annotation instanceof FormUrlEncoded) {
    //FormUrlEncoded
    if (isMultipart) {
    throw methodError("Only one encoding annotation is allowed.");
    }
    isFormEncoded = true;
    }
    }

    从上面源码可以看出,使用parseHttpMethodAndPath这个方法用于解析请求方法注解和路径参数保存到Set中

    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
    if (this.httpMethod != null) {
    throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
    this.httpMethod, httpMethod);
    }
    this.httpMethod = httpMethod;
    this.hasBody = hasBody;

    if (value.isEmpty()) {
    return;
    }

    int question = value.indexOf('?');//查询参数开始的符号
    if (question != -1 && question < value.length() - 1) {
    //如果在查询参数中使用了{},则抛出异常。
    String queryParams = value.substring(question + 1);
    Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
    if (queryParamMatcher.find()) {
    throw methodError("URL query string \"%s\" must not have replace block. "
    + "For dynamic query parameters use @Query.", queryParams);
    }
    }

    //赋值相对链接
    this.relativeUrl = value;
    //解析{}路径参数保存到Set中
    this.relativeUrlParamNames = parsePathParameters(value);
    }

    从源码可以发现,不允许在查询参数中使用{}进行占位,否则就会抛出异常,然后将请求方法中的注解值赋值给relativeUrl,通过parsePathParameters将{}路径参数保存到Set中。
    通过parseHeaders来解析头部注解。

    private Headers parseHeaders(String[] headers) {
    Headers.Builder builder = new Headers.Builder();
    for (String header : headers) {
    int colon = header.indexOf(':');
    if (colon == -1 || colon == 0 || colon == header.length() - 1) {
    throw methodError(
    "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
    }
    String headerName = header.substring(0, colon);
    String headerValue = header.substring(colon + 1).trim();
    if ("Content-Type".equalsIgnoreCase(headerName)) {
    MediaType type = MediaType.parse(headerValue);
    if (type == null) {
    throw methodError("Malformed content type: %s", headerValue);
    }
    contentType = type;
    } else {
    builder.add(headerName, headerValue);
    }
    }
    return builder.build();
    }

    看完解析方法注解后,现在来看下是如何解析参数相关注解的。源码在parseParameter中

    private ParameterHandler<?> parseParameter(
    int p, Type parameterType, Annotation[] annotations) {
    ParameterHandler<?> result = null;
    for (Annotation annotation : annotations) {//遍历参数注解
    ParameterHandler<?> annotationAction = parseParameterAnnotation(
    p, parameterType, annotations, annotation);//解析参数注解

    if (annotationAction == null) {
    continue;
    }

    if (result != null) {
    //一个参数中只允许使用一个注解,否则抛出异常
    throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
    }

    result = annotationAction;
    }

    if (result == null) {
    throw parameterError(p, "No Retrofit annotation found.");
    }

    return result;
    }

    可以看出,内部调用了parseParameterAnnotation来解析参数注解,此外,还进行了相关判断,虽然参数中可以使用多个注解,但Retrofit强制用户只能使用一个,否则抛出异常。
    parseParameterAnnotation中的源码实在太长了,这里就简单介绍下工作流程。首先根据注解来判断来校验使用上有没有错误,比如@Query注解必须在@Path和@Url后使用,使用了@Url注解那么请求方法注解中不允许设置请求路径等等;然后获取相应Converter用于转换类型(String,ResponseBody),最后初始化相应ParameterHandler返回。
    ParameterHandler这个抽象类用于处理参数,还内置了不同类型的参数转换类,源码如下:

    abstract class ParameterHandler<T> {
    abstract void apply(RequestBuilder builder, T value) throws IOException;

    //Body注解类型的转换
    static final class Body<T> extends ParameterHandler<T> {
    private final Converter<T, RequestBody> converter;

    Body(Converter<T, RequestBody> converter) {
    this.converter = converter;
    }

    @Override void apply(RequestBuilder builder, T value) {
    if (value == null) {
    throw new IllegalArgumentException("Body parameter value must not be null.");
    }
    RequestBody body;
    try {
    body = converter.convert(value);//转换为RequestBody
    } catch (IOException e) {
    throw new RuntimeException("Unable to convert " + value + " to RequestBody", e);
    }
    builder.setBody(body);//设置Body
    }
    }
    //..
    //省略了其他注解类型转换代码
    }

    调用服务接口

    以上介绍了retrofit.create(XX.class);用于创建服务方法接口的过程。现在该进行相关调用了。我们知道,创建服务方法会返回一个Call<XX>对象,通过Call<XX>可以进行相关异步同步调用。
    默认CallAdapter相关源码实现在OkHttpCall中,源码如下:

    @Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");

    okhttp3.Call call;//okhttp中的call对象
    Throwable failure;

    synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true;

    call = rawCall;
    failure = creationFailure;
    if (call == null && failure == null) {
    try {
    call = rawCall = createRawCall();//创建原始Call,即okhttp中的Call对象
    } catch (Throwable t) {
    failure = creationFailure = t;
    }
    }
    }

    if (failure != null) {
    callback.onFailure(this, failure);
    return;
    }

    if (canceled) {
    call.cancel();
    }

    //通过enqueue进行异步调用
    call.enqueue(new okhttp3.Callback() {
    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
    throws IOException {
    Response<T> response;
    try {
    response = parseResponse(rawResponse);//解析响应内容
    } catch (Throwable e) {
    callFailure(e);
    return;
    }
    callSuccess(response);
    }
    }

    从源码不难看出,首先通过createRawCall()来创建OkHttp中的Call对象,然后通过Call进行异步/同步调用,获取结果后通过parseResponse解析OkHttp中的Response,然后进行相应回调。
    createRawCall()用于创建OkHttp中的Call对象,源码如下:

    private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);//通过 serviceMethod.toRequest进行转换成Request
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);//调用newCall返回Call对象,默认callFactory为OkHttpClient,OkHttpClient也实现了okhttp3.Call.Factory接口。
    if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
    }

    parseResponse用于解析原始Response,源码如下:

    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();//获取ResponseBody

    //移除响应体
    rawResponse = rawResponse.newBuilder()
    .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
    .build();

    int code = rawResponse.code();//获取状态吗
    //code < 200 || code >= 300
    if (code < 200 || code >= 300) {
    try {
    //将整个rawBody缓冲到内存中回调
    ResponseBody bufferedBody = Utils.buffer(rawBody);
    return Response.error(bufferedBody, rawResponse);
    } finally {
    rawBody.close();
    }
    }
    //code == 204 || code == 205
    if (code == 204 || code == 205) {
    //此时没有响应体,只需回调状态
    return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
    T body = serviceMethod.toResponse(catchingBody);//通过`serviceMethod.toResponse`转换为对应对象
    //回调
    return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
    catchingBody.throwIfCaught();
    throw e;
    }
    }

    从createRawCall()和parseResponse的源码中,可以发现,通过 serviceMethod.toRequest进行转换成OkHttp中的Request,通过serviceMethod.toResponse将OkHttp中的Response转换为对应对象。
    toRequest相关源码如下:

    Request toRequest(Object... args) throws IOException {
    // RequestBuilder
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
    contentType, hasBody, isFormEncoded, isMultipart);

    //ParameterHandler数组
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    //...

    for (int p = 0; p < argumentCount; p++) {
    //遍历数组进行循环应用
    handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();//通过build()返回Request对象
    }

    toResponse源码非常简单,如下:

    T toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
    }

    默认情况下,会调用BuiltInConverters中的转换器来转换,当然,更多时候我们回去应用Gson转换器来进行转换。

    最后

    • GsonConverterFactory是怎么工作的?
      一般情况下,我们会加入addConverterFactory(GsonConverterFactory.create())来增加Gson转换功能。

      public final class GsonConverterFactory extends Converter.Factory {
      //默认Gson
      public static GsonConverterFactory create() {
      return create(new Gson());
      }
      //自己配置Gson
      public static GsonConverterFactory create(Gson gson) {
      return new GsonConverterFactory(gson);
      }

      private final Gson gson;

      private GsonConverterFactory(Gson gson) {
      if (gson == null) throw new NullPointerException("gson == null");
      this.gson = gson;
      }

      //转换ResponseBody
      @Override
      public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
      TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));//根据Type获取TypeAdapter
      return new GsonResponseBodyConverter<>(gson, adapter);//转换逻辑代码
      }

      //转换成RequestBody
      @Override
      public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
      TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));//根据Type获取TypeAdapter
      return new GsonRequestBodyConverter<>(gson, adapter);//转换逻辑代码
      }

      ResponseBody核心转换代码:

      @Override public T convert(ResponseBody value) throws IOException {
      JsonReader jsonReader = gson.newJsonReader(value.charStream());//创建JsonReader
      try {
      return adapter.read(jsonReader);//通过adapter转换
      } finally {
      value.close();//关闭流
      }
      }

      RequestBody核心转换代码:

      @Override public RequestBody convert(T value) throws IOException {
      Buffer buffer = new Buffer();
      Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
      JsonWriter jsonWriter = gson.newJsonWriter(writer);//获取JsonWriter
      adapter.write(jsonWriter, value);//adapter将value转换为Gson
      jsonWriter.close();
      return Re

    • RxJavaCallAdapterFactory是怎么工作的?
      我们还可以加入addCallAdapterFactory(RxJavaCallAdapterFactory.create())使你的代码可以进行响应式编程。

      //直接创建
      public static RxJavaCallAdapterFactory create() {
      return new RxJavaCallAdapterFactory(null);
      }

      //指定工作线程创建
      public static RxJavaCallAdapterFactory createWithScheduler(Scheduler scheduler) {
      if (scheduler == null) throw new NullPointerException("scheduler == null");
      return new RxJavaCallAdapterFactory(scheduler);
      }

      @Override
      public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
      //..
      //省略了部分源码,
      //通过getCallAdapter来获取Adapter
      CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);

      return callAdapter;
      }

      //获取CallAdapter<Observable<?>>
      private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
      Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
      Class<?> rawObservableType = getRawType(observableType);
      //..
      //省略了部分源码,
      //一般会走SimpleCallAdapter
      return new SimpleCallAdapter(observableType, scheduler);
      }

      //SimpleCallAdapter的源码如下
      static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {
      private final Type responseType;
      private final Scheduler scheduler;

      SimpleCallAdapter(Type responseType, Scheduler scheduler) {
      this.responseType = responseType;
      this.scheduler = scheduler;
      }

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

      @Override public <R> Observable<R> adapt(Call<R> call) {
      //通过Observable.create创建被观察者
      Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
      .lift(OperatorMapResponseToBodyOrError.<R>instance());
      if (scheduler != null) {
      return observable.subscribeOn(scheduler);//切换到指定线程
      }
      return observable;
      }
      }

      CallOnSubscribe中使用了RequestArbiter中包装了Call<T>对象,然后通过call.execute()同步执行,最后将结果subscriber.onNext(response)回调出去。

      static final class RequestArbiter<T> extends AtomicBoolean implements Subscription, Producer {
      private final Call<T> call;//原始的Call
      private final Subscriber<? super Response<T>> subscriber;

      RequestArbiter(Call<T> call, Subscriber<? super Response<T>> subscriber) {
      this.call = call;
      this.subscriber = subscriber;
      }

      @Override public void request(long n) {
      //...
      try {
      Response<T> response = call.execute();//call.execute()同步执行
      if (!subscriber.isUnsubscribed()) {
      subscriber.onNext(response);//onNext回调
      }
      } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (!subscriber.isUnsubscribed()) {
      subscriber.onError(t);
      }
      return;
      }

      if (!subscriber.isUnsubscribed()) {
      subscriber.onCompleted();
      }
      }

      @Override public void unsubscribe() {
      call.cancel();
      }

      @Override public boolean isUnsubscribed() {
      return call.isCanceled();
      }
      }


    本篇解读到此结束。



沪ICP备19023445号-2号
友情链接