[从零开始系列]AndroidApp研发之路-<楼外篇>Retrofit的刨根问底篇

来源:互联网 发布:精准医学大数据 编辑:程序博客网 时间:2024/05/21 22:44

文章目录:

  • 前言
  • 简介
  • Retrofit解析
    • Retrofit源码的总体概要
    • 每个类的简要分析
  • 流程梳理
  • 关于我
  • 参考

前言

写在前面

Flyabbit是一个使用Retrofit+Rxjava2+dagger2+Mvp+Material Design 快速搭建的一个app,ui是其一,更重要的是我将通过一系列的文章从项目零开始 技术选型->到封装->组件化设计->本地Maven(nexus)简单使用->自动打包(Jenkins持续集成)->单元测试->线上Bug快速修复(热修复),为大家参考部分参考,不足之处还望指出

项目 Github: https://github.com/chengzichen/Flyabbit

初衷:

之所以写[从零开始]这系列,是技术更新的太快,导致以前的一些编码和设计不在适用目前公司情况,从零开始搭建起一个更适用目前公司的框架,但是更重要的一点是在一个团队里快速上手和熟悉一个新的各类框架,以及简单原理.常言之授人予鱼不如授人与渔,在这里也是为了记录这过程,也希望能给到大家一点帮助

这篇是怎么出来的?我也不知道怎么就想着写了,当时想着写了那就当<楼外篇>吧

  • [x] 从零开始的AndroidApp研发之路-网络请求的封装
  • [x] 从零开始的AndroidApp研发之路-<楼外篇>Retrofit的刨根问底篇
  • [ ] 从零开始的AndroidApp研发之路-MVP设计之路
  • [ ] 从零开始的AndroidApp研发之路-Base抽取之路
  • [ ] 从零开始的AndroidApp研发之路-组件化,持续集成
  • [ ] 从零开始的AndroidApp研发之路-单元测试

简介

相信大家也知道Retrofit代码解耦和设计模式的应用简直是代码范例,Retrofit+Rxjava+Okhttp这三剑客也被大家使用这么久了

Retrofit 2.0

  • A type-safe HTTP client for Android and Java

Retrofit解析

Retrofit源码的总体概要

在此之前我先道个欠,由于个人的疏忽,md排版的问题,没能认真的审查,导致该文章内容只有一半显示,而且内容没能连接上,为此表示道歉。

  1. 相信大家也知道Retrofit代码解耦和设计模式的应用简直是代码范例,下面的源码分析都基于Retrofit-v2.3.0,首先用一波数据让大家简单了解Retrofit源码

    1. Retrofit的jar包只有89k(89k能干嘛)
    2. Retrofit源码的类的个数合计41个
    3. Retrofit源码的方法的个数合计513个()
    4. Retrofit代码的涉及的常见模式不完全统计有7种
  2. 这里给列出所有的类进行分类了(41个),后面都做了一一的解释分析

    • 其中有24个注解类

      • 请求方式注解
        • GET
        • POST
        • DELETE
        • PUT
        • PATCH
        • HEAD
        • OPTIONS
      • 使用方法上部注解
        • HTTP
        • FormUrlEncoded
        • Headers
        • Multipart
        • Streaming
      • 方法参数类使用的注解
        • Url
        • Body
        • Path :
        • Field
        • FieldMap :
        • Header
        • HeaderMap
        • Part
        • PartMap
        • Query
        • QueryMap
        • QueryName
    • 还剩下17个类

      • 其中4个接口(还有一个package-info忽略)
        • Call
        • CallAdapter
        • Callback
        • Converter
      • CallAdapter.Factory实现类有两个
        • DefaultCallAdapterFactory
        • ExecutorCallAdapterFactory
      • 其中Call实现类一个
        • OkHttpCall
      • Converter.Factory实现类一个
        • BuiltInConverters
      • 工具类一个
        -Utils
      • 异常类一个
        • HttpException
      • 最后剩下的6个类就是比较关键的几个类了
        • Retrofit
        • Platform
        • ParameterHandler
        • RequestBuilder
        • ServiceMethod
        • Response
  3. 涉及的设计模式有

    • 动态代理
    • 策略模式
    • 观察者模式
    • 适配器模式
    • Builder模式
    • 工厂模式
    • 装饰模式
    • 外观模式

    …(我目前了解的有这些,如有错误,请斧正)

    设计模式链接:http://www.runoob.com/design-pattern/facade-pattern.html

  4. 最后应该是源码的流程分析

    1. 构造者模式创建Retrifit对象初始化okHttpClient,ConverterFactory,CallAdapterFactory
    2. 调用retrofit.create()方法,使用代理模式拦截service调用的每个方法
    3. 获取service中Method上所有相关的注解参数保存在ServiceMethod对象中
    4. 再通过ServiceMethod对象创建OkhttpCall对象,内部调用Okhttp.call实现请求.
    5. 最后通过适配器模式,用初始化时保存到ServiceMethod中的CallAdapter对象中的adapt(OkhttpCall)方法,返回我们声明的接口的service中方法返回值.

每个类的简要分析

以下几类都是请求方式:

  • GET(SELECT):从服务器取出资源(一项或多项)
  • POST(CREATE):在服务器新建一个资源。
  • DELETE(DELETE):从服务器删除资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • HEAD :获取资源的元数据。
  • OPTIONS: 获取信息,关于资源的哪些属性是客户端可以改变的。

  • HTTP: 官方给出的定义:为请求使用定制的HTTP请求的注解
    示例:

 HTTP(method = "CUSTOM", path = "custom/endpoint/")   Call<ResponseBody> customEndpoint();//或者 HTTP(method = "DELETE", path = "remove/", hasBody = true)   Call<ResponseBody> deleteObject(@Body RequestBody object);
  • Url:URL将替换BaseUrl
  @GET  Call<ResponseBody> list(@Url String url);  
  • Body :当您想要直接控制一个post/put请求的请求体时(而不是作为请求参数或表单样式的请求体发送),在服务方法param上使用该注释。该对象将使用Retrofit改进改造实例Converter转换器,转换器进行序列化,结果将被直接设置为请求主体。

白话: 也就是说需要创建一个Converter转换器,把需要提交的数据序列化以下,再放入body中去

一般情况下GsonConverter支持了序列化为json的就够了,特殊情况只需要重写Converter就可以,当然也支持:

Gson: com.squareup.retrofit2:converter-gson Jackson: com.squareup.retrofit2:converter-jackson Moshi: com.squareup.retrofit2:converter-moshi Protobuf: com.squareup.retrofit2:converter-protobuf Wire: com.squareup.retrofit2:converter-wire Simple XML: com.squareup.retrofit2:converter-simplexml

示例 :

    //这里是默认使用的GsonConverter,所以@Body 传TeamInviteRequestBean对象就可以转成Json   @Headers({"Content-Type: application/json;charset=UTF-8","Accept: application/json"})//需要添加头@POST("group-rest/groupInvitation/push")Flowable<ApiResponse<String>> teamInvite(@Body TeamInviteRequestBean teamInviteRequestBean);
  • Path : 在URL路径段中指定的替换。值被转换为字符串和URL编码,(与Converter类中stringConverter方法有关,如果没有找到合适的转化器,将会使用Object的toString方法)

示例:

    GET("/image/{id}")    Call<User> example(@Path("id") int id);
  • Field :用于Post方式传递参数,需要在请求接口方法上添加@FormUrlEncoded,即以表单的方式传递参数

示例:

@FormUrlEncoded@POST("user/edit")Call<User> example(@Field("name") String name);
  • FieldMap : 用于Post方式传递参数,需要在请求接口方法上添加@FormUrlEncoded,即=以表单编码的请求命名的键/值对
@FormUrlEncoded@POST("user/edit")Call<User> things(@FieldMap Map<String, String> fields);
  • FormUrlEncoded :请求主体将使用表单URL编码提交。用这个注释做的请求将有 application/x-www-form-urlencoded 的MIME
    类型

示例同上.
- Header : 用于替换http头部

示例 : <pre><code>@GET("user")Call<User> foo(@Header("Authorization") String authorization)@GET("user")Call<User> foo(@Header("Accept-Language") String lang) </code></pre>
  • HeaderMap: 跟@Header作用一样,@Header是作为请求方法的参数传入,@HeaderMap只是使用Map的方式添加

示例:

    GET("/search")    Call<User> foo()(@HeaderMap Map<String, String> headers);

-Headers@Header作用一样,只是使用方式不一样,@Header是作为请求方法的参数传入,@Headers是以固定方式直接添加到请求方法上

示例:

    @Headers("Cache-Control: max-age=640000")    @GET("user")    Call<User> foo();    或者    @Headers({      "X-Foo: Bar",      "X-Ping: Pong"     })    @GET("user")    Call<User> foo();
  • Multipart :请求体是多部分的组成的。应该将部件声明为参数
    带有@Part,并允许多个,一般用于多图文一起提交的情况
    上一篇文章中也有讲过.
    示例 :
public interface IUserBiz{    @Multipart    @POST("register")    Call<User> registerUser(@Part MultipartBody.Part photo, @Part("username") RequestBody username, @Part("password") RequestBody password);    //MultipartBody多部分组成 ,RequestBody单个}
  • Part : 表示多部分请求的单个部分 .

示例:

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

- PartMap : 表示多部件请求的名称和值部分。同@Part是样的,只是以Map键值对形式提交,作为键或值是不允许的null的,

示例:

 
@Multipart
@POST("/upload")
Call<ResponseBody> upload(
@Part("file") RequestBody file,
@PartMap Map<String, RequestBody> params);

  • Query : 用于Http Get请求传递参数 :类似拼接问号后面一段: http://www.xxx.com/user?username=zhangsan

示例 :

@GET("group/users")Call example(@Query("user") int userId);
  • QueryMap : 与 @Query 相同都是用于Http Get请求传递参数,只是多个参数放在Map提交

示例

@GET("/group/{id}/users") List<USer> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
  • QueryName : 添加一个没有值的URL的查询参数.
@GET("/friends") Call<ResponseBody> friends(@QueryName String filter);

或者 Array/Varargs:多个

@GET("/friends") Call<ResponseBody> friends(@QueryName String... filters);
  • Streaming : 将 返回结果转为byte[]

注意: 如果下载一个非常大的文件,Retrofit会试图将整个文件读进内存。为了避免这种现象的发生,我们添加了一个特殊的注解来声明请求,那就是@Streaming

具体参考:

Retrofit 2 - 如何从服务器下载文件(小鄧子)

Retrofit 2.0 超能实践(四),完成大文件断点下载

剩余17个类

  • 其中4个接口(还有一个package-info忽略)

    • Call :有几个关键的方法:

      • 方法execute() :同步执行请求
      • enqueue() :异步执行请求
      • cancel() :取消当前请求
      • clone() :克隆当前请求
      • CallAdapter : 看名字都知道是Call的适配器(只能这样强行),最终处理OkHttpCall实例并返回接口Method, 用来适配Rxjava,Java8,Guava等等,比如像以前Retrofit可能还不支持Rxjava返回Flowable或者Observable或者以后要支持其他的返回结果类型,都可以使用该重写该适配器来添加.有两个方法和一个内部类
      • Type responseType() :
        这里通过ParameterizedType获取java泛型参数类型,也就是获取response返回参数的类型
      • T adapt(Call<R> call); :
        这个方法是将传进来的call转化为对应的类型,比如转成:rxjava需要的Flowable或者Observable(这里使用到了适配器模式,策略模式)(这个方法比较重要)
      • 工厂类CallAdapter.Factory
        -CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,Retrofit retrofit) : CallAdapter.Factory就通过这个方法返回一个CallAdapter对象

        • Type getParameterUpperBound(int index, ParameterizedType type):在索引中提取通用参数的上限
          从类型(只是获取参数类型相当于是一个工具方法可以忽略)
        • Class<?> getRawType(Type type) : 从type中提取原始类类型(只是获取原始类型相当于是一个工具方法可以忽略)
      • Callback : 这就是一个再正常不过的一个结果回调接口

      • void onResponse(): 有响应时的回调方法
      • void onFailure() : 失败的情况的回调方法
      • Converter : 转化器,就是提供responseBody,responseBody的转换的接口,也就是说在处理结果请求前和后都能分别对请求参数和请求结果进行合理的改变.(在这里可以自定义对请求加密和解密)
      • Converter<ResponseBody, ?> responseBodyConverter() //请求后对结果进行解析或者解密等操作,可以参考 GsonResponseBodyConverter
      • Converter<?, RequestBody> requestBodyConverter()//请求前对请求参数进行格式化(比如格式化为Json格式)或者加密,可以参考 GsonRequestBodyConverter

      • CallAdapter.Factory实现类有两个

        1. DefaultCallAdapterFactory :对 CallAdapter.Factory实现类,默认的
        2. ExecutorCallAdapterFactory : (重点:装饰模式,工厂模式)ExecutorCallbackCall是用来切换线程和调用okhttpCall方法,调用okhttpCall与okhttp打交道了
          final class ExecutorCallAdapterFactory extends CallAdapter.Factory {      final Executor callbackExecutor;      ExecutorCallAdapterFactory(Executor callbackExecutor) {        this.callbackExecutor = callbackExecutor;      }      @Override      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {        if (getRawType(returnType) != Call.class) {          return null;        }        final Type responseType = Utils.getCallResponseType(returnType);        return new CallAdapter<Object, Call<?>>() {          @Override public Type responseType() {            return responseType;          }          @Override public Call<Object> adapt(Call<Object> call) {            return new ExecutorCallbackCall<>(callbackExecutor, call);          }        };      }    //以上代码就是简单工厂模式,这个不用解释了吧.      static final class ExecutorCallbackCall<T> implements Call<T> {        final Executor callbackExecutor;        final Call<T> delegate;        ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {          this.callbackExecutor = callbackExecutor;          //delegate是从类retrofit中传过来的就是OkhttpCall,          this.delegate = delegate;        }        @Override public void enqueue(final Callback<T> callback) {          checkNotNull(callback, "callback == null");          delegate.enqueue(new Callback<T>() {            @Override public void onResponse(Call<T> call, final Response<T> response) {              callbackExecutor.execute(new Runnable() {//callbackExecutor实现切换到主线程,callbackExecutor也就是Platform中MainThreadExecutor了(下面有介绍)                @Override public void run() {                  if (delegate.isCanceled()) {                    // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));                  } else {                    callback.onResponse(ExecutorCallbackCall.this, response);                  }                }              });            }            //以上代码就是装饰模式了,不知道看出来没有,delegate是从类retrofit中传过来的就是OkhttpCall,            //也就是不改变其结构OkhttpCall的情况下用ExecutorCallbackCall扩展OkhttpCall切换到主线程的功能          ....          });        }        ....      }    }

      设计模式请参考这里:装饰器模式

      • 其中Call实现类一个
        1. OkHttpCall : 这个不用说了,封装了okhttp的实现类要注意的是okhttp3.Call是通过serviceMethod构建出来的.
                private okhttp3.Call createRawCall() throws IOException {Request request = serviceMethod.toRequest(args);okhttp3.Call call = serviceMethod.callFactory.newCall(request);if (call == null) {  throw new NullPointerException("Call.Factory returned null.");}return call;}
      • Converter.Factory实现类一个
        1. BuiltInConverters : 是Retrofi默认的转化器 ,默认responseBodyConverter返回结果为Buffer,也可以用@Streaming注解设置为Streaming类型
      final class BuiltInConverters extends Converter.Factory {  @Override  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,      Retrofit retrofit) {    if (type == ResponseBody.class) {      return Utils.isAnnotationPresent(annotations, Streaming.class)          ? StreamingResponseBodyConverter.INSTANCE          : BufferingResponseBodyConverter.INSTANCE;    }    if (type == Void.class) {      return VoidResponseBodyConverter.INSTANCE;    }    return null;  }    ........   }}
      • 工具类一个:Utils (这里就不展示了)
      • 异常类一个:HttpException(这里就不展示了)

    最后剩下的6个类就是比较关键的几个类了

    • Retrofit : Retrofit 主要类(构造者模式和适配器模式,动态代理模式,门面模式),这些模式巧妙的运用是非常值得我们学习的.

      public <T> T create(final Class<T> service) {    Utils.validateServiceInterface(service);//验证是否是Interface    if (validateEagerly) {      eagerlyValidateMethods(service);    }    //这里使用了动态代理,第一个参数是指定一个类加载器,第二个给出定义的接口的类类型,传入一个InvocationHandler回调    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },        new InvocationHandler() {          private final Platform platform = Platform.get();//这里是获取环境对应的平台,Handler handler = new Handler(Looper.getMainLooper())并初始化了一个主线程的handle            //这个invoke方法会在代理对象的方法中调用,第一个参数就是代理对象          @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<Object, Object> serviceMethod =                (ServiceMethod<Object, Object>) loadServiceMethod(method);            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);            return serviceMethod.callAdapter.adapt(okHttpCall);//这里使用了适配器模式,这里的callAdapter          }        });  }
    • Platform : 根据不同的运行环境还提供了不同的Executor(),这也是很值得我们学习的地方

        private static Platform findPlatform() {    try {      Class.forName("android.os.Build");      if (Build.VERSION.SDK_INT != 0) {//如果是android环境        return new Android();      }    } catch (ClassNotFoundException ignored) {    }    try {      Class.forName("java.util.Optional");//如果是java8环境      return new Java8();    } catch (ClassNotFoundException ignored) {    }    return new Platform();  }             .......   static class Android extends Platform {    @Override public Executor defaultCallbackExecutor() {      return new MainThreadExecutor();//这里的MainThreadExecutor在发挥着切换线程的作用    }    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {      if (callbackExecutor == null) throw new AssertionError();      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);      }    }  }
    • ParameterHandler :根据接口Method参数的注解所生成的参数处理Handler数组

      这里参数拼接就是和上面注解类都基本能对应上

    • RequestBuilder : 通过method,Url,headers, contentType, hasBody,
      isFormEncoded,isMultipart拼接Header,通过ParameterHandler添加参数(如果有)并返回okhttp3.Request对象

       Request build() {//在build方法之前需要的参数都已经准备好了    HttpUrl url;    HttpUrl.Builder urlBuilder = this.urlBuilder;    if (urlBuilder != null) {      url = urlBuilder.build();    } else {      // No query parameters triggered builder creation, just combine the relative URL and base URL.      //noinspection ConstantConditions Non-null if urlBuilder is null.      url = baseUrl.resolve(relativeUrl);      if (url == null) {        throw new IllegalArgumentException(            "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);      }    }    RequestBody body = this.body;    if (body == null) {      // Try to pull from one of the builders.      if (formBuilder != null) {        body = formBuilder.build();      } else if (multipartBuilder != null) {        body = multipartBuilder.build();      } else if (hasBody) {        // Body is absent, make an empty body.        body = RequestBody.create(null, new byte[0]);      }    }    MediaType contentType = this.contentType;    if (contentType != null) {      if (body != null) {        body = new ContentTypeOverridingRequestBody(body, contentType);      } else {        requestBuilder.addHeader("Content-Type", contentType.toString());      }    }    return requestBuilder//这里是使用okhttp3.Request.Builder,构建请求对象        .url(url)        .method(method, body)        .build();  }
    • ServiceMethod :
      这个类比较复杂了 ,在这个类里完成请求参数的解析,组装,拼接,和保存了将一个method转化为Call的所有的信息,有以下重要的属性:

      • okhttp3.Call.Factory callFactory 是用来创建真正要执行的okhttp3.Call的工厂类,可以Retrofit.Builder中设置,如果不设置,默认会new一个OkHttpClient作为callFactory
      • Converter responseConverter:参照上面说明
      • ParameterHandler parameterHandlers :参照上面说明
      • CallAdapter callAdapter : :参照上面说明
        Request toRequest(@Nullable Object... args) throws IOException {    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,        contentType, hasBody, isFormEncoded, isMultipart);//先拼接Header    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;    int argumentCount = args != null ? args.length : 0;    if (argumentCount != handlers.length) {      throw new IllegalArgumentException("Argument count (" + argumentCount          + ") doesn't match expected count (" + handlers.length + ")");    }    for (int p = 0; p < argumentCount; p++) {      handlers[p].apply(requestBuilder, args[p]);//遍历拼接参数    }    return requestBuilder.build();//最后组装头部和参数  }
    • Response : An HTTP response 请求处理成功和失败情况

流程梳理

以上就是每个类的大概说明,涉及的设计模式有:动态代理,策略模式,观察者模式,适配器模式,Builder模式,工厂模式,装饰模式…(我目前了解的有这些,如有错误,请斧正),可拓展的适配器类型有 RxjavacalllAdapterjava8callAdapter GuavacallAdapter DefultCallAdapter ExecutorCallAdapter等,接下来我们从设计模式结合流程来分析Retrofit,其实上面每个类也介绍的差不多了,这里再把流程梳理一遍,对Retrofit的认识算是更进一步了.想要收获更多只能直接看代码了.

照常理,先看看Retrofit简单用法

Retrofit retrofit = new Retrofit.Builder()
.baseUrl(“www.baidu,com”)
.client(okHttpClient)//这里如果不添加,okHttpClient,Retrofit会创建一个默认的okHttpClient
//增加返回值为String的的Converter转换器
.addConverterFactory(ScalarsConverterFactory.create())
//增加返回值为Gson的Converter转换器
.addConverterFactory(GsonConverterFactory.create())
//增加返回值为Oservable的Call适配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();

UserApi userApi = retrofit.create(UserApi.class);//这里采用的是Java的动态代理模式
Call call = userApi.getUser(“zhangshan”);//传入我们请求的值

  1. 首先从上面来看,
    这里使用了Builder模式构建Retrofit对象时并我们传入了

    • okHttpClient(这里如果不添加,okHttpClient,Retrofit会创建一个默认的okHttpClient,代码链接@retrofit#build())

    • ConverterFactory(ScalarsConverterFactory,GsonConverterFactory,这里如果没有传的话默认的是BuiltInConverters,没错就是它因为Retrofit中只有他这么一个实现了Converter的独苗子,代码链接@Retrofit#build)

    • CallAdapterFactory(没有添加话默认为ExecutorCallAdapterFactory或者DefaultCallAdapterFactory,代码链接@Platform#defaultCallAdapterFactory)
  2. 当我们创建完毕retrofit对象后所有的事情都交给了retrofit对象,这种设计模式我们叫外观模式(外观模式 Facade Pattern:隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口),后面调用了retrofit.create()方法(主要的实现基本也就在这里了)
    public <T> T create(final Class<T> service) {        Utils.validateServiceInterface(service);//验证是否是Interface        if (validateEagerly) {          eagerlyValidateMethods(service);//验证方法        }        //这里使用了动态代理,第一个参数是指定一个类加载器,第二个给出定义的接口的类类型,传入一个InvocationHandler回调        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },            new InvocationHandler() {              private final Platform platform = Platform.get();//这里是获取环境对应的平台,Handler handler = new Handler(Looper.getMainLooper())并初始化了一个主线程的handle                //这个invoke方法会在代理对象的方法中调用,第一个参数就是代理对象              @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);                }//这里是判断是否Object的方法(过滤掉)                if (platform.isDefaultMethod(method)) {                  return platform.invokeDefaultMethod(method, service, proxy, args);                }/这里是判断是否Object的默方法(过滤掉)                ServiceMethod<Object, Object> serviceMethod =                    (ServiceMethod<Object, Object>) loadServiceMethod(method);                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);                return serviceMethod.callAdapter.adapt(okHttpCall);//这里使用了适配器模式,这里的callAdapter              }            });      }

首先进来就验证参数service是一个Interface和验证里面的方法,方法返回的是动态代理的对象,也就是说调用service的某个请求方法时在这里都会被proxy拦截(动态代理模式)在proxy只要关心

  ServiceMethod<Object, Object> serviceMethod =                    (ServiceMethod<Object, Object>) loadServiceMethod(method);                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);                return serviceMethod.callAdapter.adapt(okHttpCall);//这里使用了适配器模式,这里的callAdapter

ServiceMethod在这个类里完成请求参数的解析,组装,拼接,和保存了将一个method转化为Call的所有的信息,也就是说loadServiceMethod(method)将一个method转化为Call的所有的信息保存到ServiceMethod中(包括okhttp3.Call.Factory,Converter

            ServiceMethod loadServiceMethod(Method method) {        ServiceMethod result;        synchronized (serviceMethodCache) {          result = serviceMethodCache.get(method);          if (result == null) {//判断是否内存中有存在            result = new ServiceMethod.Builder(this, method).build();            serviceMethodCache.put(method, result);          }        }        return result;      }

先判断内存中时是否存在,没有的话通过 new ServiceMethod.Builder()构建,如果想看是怎么构建的一个ServiceMethod对象请看ServiceMethod#build()

接下来通过new OkHttpCall<>(serviceMethod, args),通过ServiceMethod对象创建OkHttpCall对象,而OkHttpCall是封装了okhttp的实现类,然后通过okhttp3.Callexecute或者enqueue做实际请求,这个过程也是比较简单的

     private okhttp3.Call createRawCall() throws IOException {        Request request = serviceMethod.toRequest(args);        okhttp3.Call call = serviceMethod.callFactory.newCall(request);        if (call == null) {          throw new NullPointerException("Call.Factory returned null.");        }        return call;      }

最后的话就是serviceMethod.callAdapter.adapt(okHttpCall);//这里使用了适配器模式,这里的CallAdapter是在构建Retrofit的时候传入CallAdapterFactory(工厂模式)生产出来的,然后调用adapt(okHttpCall)会将OkHttpCall返回的结果转换成我们声明的接口的返回值.

但是如果没有传入CallAdapterFactory就默认使用的是ExecutorCallAdapterFactory(工厂模式)生产的CallAdapter对象CallAdapter中包括了一个ExecutorCallbackCall.而ExecutorCallbackCall是在不改变其结构OkhttpCall的情况下用ExecutorCallbackCall扩展OkhttpCall切换到主线程的功能(使用handle).最终返回Response对象或者对应的结果回调给Callback,也就是示例中的Call<String> call = userApi.getUser("zhangshan");

现在目前用的比较多的RxJava2CallAdapterFactory(我这里是用的是Rxjava2),也可以看看是怎么实现的,有没有什么可以值得学习的地方

RxJava2CallAdapterFactory也是实现了CallAdapter的实现类,直接上代码
 @Override public Object adapt(Call<R> call) {    Observable<Response<R>> responseObservable = isAsync        ? new CallEnqueueObservable<>(call)        : new CallExecuteObservable<>(call);    Observable<?> observable;    if (isResult) {      observable = new ResultObservable<>(responseObservable);    } else if (isBody) {      observable = new BodyObservable<>(responseObservable);    } else {      observable = responseObservable;    }    if (scheduler != null) {      observable = observable.subscribeOn(scheduler);    }    if (isFlowable) {      return observable.toFlowable(BackpressureStrategy.LATEST);    }    if (isSingle) {      return observable.singleOrError();    }    if (isMaybe) {      return observable.singleElement();    }    if (isCompletable) {      return observable.ignoreElements();    }    return observable;  }

一定有疑问怎么返回这么多的类型的ObservableFlowable,这里和Rxjava1.0,RxJavaCallAdapterFactory是不一样的,首先判断是否是异步的返回CallEnqueueObservable(最终调用的是Okhttp.callenqueue的方法,然后回调Observable,onNext()或者onError())同步的CallExecuteObservable(最终调用的是Okhttp.callexecute的方法,然后回调Observable,onNext()或者onError()),再根据不同情况返回ResultObservable,BodyObservable(这两个类是对responseObservable的拓展了一些功能),当然也适配了Flowable支持了背压.(当然这也是策略模式)
RxJavaCallAdapterFactor,用的地方不同.然后我们拿到我们声明的接口的(Observab或者Flowable)返回值,类似Flowable<String> call = userApi.getUser("zhangshan");.

最后看看下面的图,结合下上文在回味一下,感受下Retrofit代码解耦和设计模式的应用,简直是代码范例,心里真是美滋滋..

image

图片来自:Retrofit分析-漂亮的解耦套路 by stay4it

关于我

  • Github:https://github.com/chengzichen

  • CSDN : http://blog.csdn.net/chengzichen_

  • 个人博客 : https://chengzichen.github.io/

参考

文件下载

  • Retrofit 2 - 如何从服务器下载文件(小鄧子)

  • Retrofit 2.0 超能实践(四),完成大文件断点下载

Retrofit原理解析

  • Retrofit分析-漂亮的解耦套路
  • Retrofit2 完全解析 探索与okhttp之间的关系