Android开发Retrofit源码分析

目录
  • 项目结构
  • retrofit 使用
  • Retrofit #create
  • ServiceMethod #parseAnnotations
  • HttpServiceMethod#parseAnnotations
    • 第二种 非Kotlin协程情况
    • DefaultCallAdapterFactory#get
    • 第一种 Kotlin协程情况
  • 总结

项目结构

把源码 clone 下来 , 可以看到 retrofit 整体结构如下

图 http包目录下就是一些http协议常用接口 , 比如 请求方法 url , 请求体, 请求行 之类的

retrofit 使用

把retrofit使用作为分析的切入口吧 , retrofit单元测试使用如下

public final class BasicCallTest {
    @Rule public final MockWebServer server = new MockWebServer();
    interface Service {
        @GET("/") Call<ResponseBody> getBody();
    }
    @Test public void responseBody() throws IOException {
        Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(server.url("/"))
            .build();
        Service example = retrofit.create(Service.class);
        server.enqueue(new MockResponse().setBody("1234"));
        Response<ResponseBody> response = example.getBody().execute();
        assertEquals("1234", response.body().string());
    }
}

Retrofit 构建 , 以构建者模式构建出Retrofit

可以看到builer可以配置baseUrl , 回调线程池 , 还有一些适配器的工厂 , 这些适配器的作用后面说

Retrofit #create

从create 方法开始分析 , 跟进看下create 方法

public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
        service.getClassLoader(),
        new Class<?>[] {service},
        new InvocationHandler() {
            private final Object[] emptyArgs = new Object[0];
            @Override
            public @Nullable Object invoke(Object proxy, Method method, @Nullable 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);
                }
                args = args != null ? args : emptyArgs;
                Platform platform = Platform.get();
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
            }
        });
}

service 是请求的接口的class , 动态代理只能是接口 , 所以validateServiceInterface 先验证是不是接口 , 不是接口则抛异常。

method.getDeclaringClass() 获取声明类的Class。

比如 A类 有个method , method.getDeclaringClass() 返回为A.class , 如果method声明类是Object.class 则直接method.invoke , 往下执行毫无意义。

Platform#get()会根据当前平台获取Platform 。

有点类似状态模式思想 , 根据当前的平台选择合适的子类

public boolean isDefaultMethod(Method method) {
    return method.isDefault();
    }

isDefault , 在接口类型中以default关键字声明 则返回true, 比如

interface InterfaceWithDefault {
    void firstMethod();
    default void newMethod() {
        System.out.println("newMethod");
    }
}

所以此处会返回 false 接着调用 loadServiceMethod。

ServiceMethod #parseAnnotations

跟进ServiceMethod #parseAnnotations

  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

根据当前的方法信息构建出RequestFactory , 然后把具体实现细节交给HttpServiceMethod 处理 , HttpServiceMethod 继承自ServiceMethod , 有三个子类 。

我们在Api.class定义的方法 , 解析并不是由HttpServiceMethod 完成 , 而是由RequestFactory去处理的 , 比如解析方法的注解。

更多的解析方法如下

方法解析的细节就不说了 , 继续看RequestFactory 这个类 , 这个类的作用难道就是负责方法信息的解析 , 感觉和名字不太符合 , RequestFactory 顾名思义应该是用来构建Request的工厂 , 果不其然内部还有个 create 方法 , 用来构建okhttp3.Request的

  //RequestFactory #create
okhttp3.Request create(Object[] args) throws IOException {
    return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
  }

就只有这一个create方法 , 难道retrofit 就只能使用okhttp来负责网络请求 ? 答案是肯定的 , 从最开始的 loadServiceMethod(method).invoke(args)也可以看出 , 方法里面只构建出OkHttpCall 没提供api可以让我们切换到其他的网络请求库。

但是 , Call 又抽象成接口的形式 ,如下, 这么做的目的可能是以后便于框架的维护

沿途风景再美丽 , 也要回到主线路 , 继续分析 HttpServiceMethod#parseAnnotations

HttpServiceMethod#parseAnnotations

这个方法太长 , 贴关键代码吧

 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;
    boolean continuationIsUnit = false;
    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType =
          Utils.getParameterLowerBound(
              0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        continuationWantsResponse = true;
      }
    } else {
      //非kt 协程情况
      adapterType = method.getGenericReturnType();
    }
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
        //非kt 协程情况
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable,
              continuationIsUnit);
    }
  }

构建出HttpServiceMethod分两种情况 :

  • kotlin 协程情况
  • 非Kotlin 协程情况

第二种 非Kotlin协程情况

第一种情况稍许复杂 , 先分析第二种

adapterType = method.getGenericReturnType();

 @GET("/") Call<ResponseBody> getBody();

如果是上面代码 , method.getGenericReturnType() = Call , 然后根据方法的返回值类型 / 方法注解信息 , 构建出CallAdapter 。

createCallAdapter() 方法会使用 CallAdapter.Factory 构建CallAdapter , 因为初始化retrofit的时候没有配置CallAdapter.Factory , 所以会使用默认的DefaultCallAdapterFactory。

最终会进入DefaultCallAdapterFactory#get 。

DefaultCallAdapterFactory#get

这个方法作用就是返回CallAdapter , 修改下源码加入两个打印。

  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
    System.out.println("TAG" + " ->" + "returnType = " +getRawType(returnType) .getSimpleName());
    System.out.println("TAG" + " ->" + "responseType = " +getRawType(responseType) .getSimpleName());
    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }
      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

运行可以看到以下打印信息

returnType = Call ,responseType =ResponseBody 。

总结一下 , returnType就是方法返回值 , responseType 就是方法返回值上的泛型 DefaultCallAdapterFactory会根据平台环境去构建。

以Android24分析 , DefaultCallAdapterFactory(Executor callbackExecutor) , 构造方法中 , 线程池为主线程池 , 在retrofit初始化的时候添加到 到callAdapterFactories 集合中。

至此 , CallAdapterFactory 和 CallAdapter 分析完了 , 总结下就是给Call (retrofit内存只有OkHttpCall 作为唯一实现类)做适配 , 让其可以在 Rxjava / 协程 等各个环境中使用 Call。

非kt 协程情况下 , parseAnnotations 方法最终返回的是将requestFactory , callFactory , responseConverter, callAdapter 封装好的CallAdapted 对象。

再次回到梦开始的地方Retrofit#create 方法 , loadServiceMethod获取的ServiceMethod最终实现类为CallAdapted , 获取之后会调用invoke方法 , invoke是一个final方法 , 里面构建了OkHttpCall , 然后调用了adapt方法 , adapt中调用了callAdapter.adapt(call)。

   @Override
    protected ReturnT adapt(Call&lt;ResponseT&gt; call, Object[] args) {
      return callAdapter.adapt(call);
    }

这里的ReturnT 就是ExecutorCallbackCall<>(executor, call) 对象 , 所以 example.getBody().execute() 就是调用ExecutorCallbackCall#execute方法

 //ExecutorCallbackCall#execute
 public Response<T> execute() throws IOException {
      return delegate.execute();
    }

delegate为OkHttpCall , 所以就调用到OkHttpCallCall#execute方法 , 这里就转给Okhttp去请求网络加载数据了 , 代码就不贴了 , 我们看下网络请求之后 , 数据Response 的处理 , 关键代码OkHttpCall#parseResponse。

 Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    }
  }

responseConverter 在 HttpServiceMethod#parseAnnotations 方法中获取 , 回应数据转换器 , 把数据转换成我们可以直接使用的对象 , 比如我们常用的 GsonConverterFactory。

最后把转换好之后的数据 , 封装成Response对象返回。

response.body()就是responseConverter 转换后的数据 来张大致流程图感受下吧

第一种 Kotlin协程情况

其实大致流程第二种情况分析的差不多了 , 接下来分析下Retrofit对于kotlin的特殊处理吧。

 if (Utils.getRawType(parameterType) == Continuation.class) {
              isKotlinSuspendFunction = true;
              return null;
            }

协程挂起方法 , 第一个参数为Continuation , 所以判断是不是挂起方法也很简单 , 根据ResponseType 去构建协程专用的HttpServiceMethod , 主要有两类。

  • SuspendForResponse , 对应type为Continuation<Response>
  • SuspendForBody , 对应type为Continuation

这里看下 SuspendForBody 实现 , 套娃情况就不分析了。

如果是这样使用 , 最终会调到SuspendForBody #adapt。

 @Override
    protected Object adapt(Call<ResponseT> call, Object[] args) {
      call = callAdapter.adapt(call);
      Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
      try {
         //去掉干扰代码 , 仅保留这个
          return KotlinExtensions.awaitNullable(call, continuation);
      }
    }

这个地方就很关键了 , java 直接调kotlin 协程 suspend 方法。

KotlinExtensions.awaitNullable 会调到KotlinExtensions#await方法。

retrofit与协程适配的细节都在 KotlinExtensions这个类里。

进入await , 可以看到使用suspendCancellableCoroutine把回调装换成协程。

@JvmName("awaitNullable")
suspend fun <T : Any> Call<T?>.await(): T? {
    return suspendCancellableCoroutine { continuation ->
        continuation.invokeOnCancellation {
            cancel()
        }
        enqueue(object : Callback<T?> {
            override fun onResponse(call: Call<T?>, response: Response<T?>) {
                if (response.isSuccessful) {
                    continuation.resume(response.body())
                } else {
                    continuation.resumeWithException(HttpException(response))
                }
            }
            override fun onFailure(call: Call<T?>, t: Throwable) {
                continuation.resumeWithException(t)
            }
        })
    }
}

其实内部也是调用 OkHttp Call.enqueue() , 只不过是用suspendCancellableCoroutine给协程做了一层包装处理

通过 suspendCancellableCoroutine包装之后使用就很简单了。

 GlobalScope.launch {
            try {
                val result = xxxApi.getXxx()
            } catch (exception: Exception) {
            }
        }

总结

Call 这个接口用于与网络请求库做适配 , 比如Okhttp。

CallAdapter 用于retrofit 与各种环境搭配使用做适配 , 比如rxjava / 协程 / java。

Converter 用于将请求结果转换实体类Bean 或者其他。

用到的设计模式有: 动态代理/静态代理 / 构建者 / 工厂 / 适配器 / 状态 等。

以上就是Android开发Retrofit源码分析的详细内容,更多关于Android Retrofit源码分析的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android Retrofit框架的使用

    Retrofit介绍 Retrofit是Square开源的一款基于OkHttp(也是他家的)封装的网络请求框架,主要的网络请求还是OkHttp来完成,Retrofit只是对OkHttp进行了封装,可以让我们更加简单方便的使用,目前大部分公司都在使用这款框架,Retrofit的原理也是面试必问的问题之一了,所以我们不仅要会使用,也要对其实现原理有一个大概的了解. 本片文章从使用角度来说,不对的地方希望大家在评论区交流,我会及时改进,共同进步,文章中的demo可以从github下载. Retrofi

  • android Retrofit2网络请求封装介绍

    目录 1. Retrofit使用 2. Retrofit封装 3. RetrofitUtil使用 最后 1. Retrofit使用 Retrofit是一个现在网络请求框架,先来说一下怎么使用 网络权限(添加到AndroidManifest.xml) <uses-permission android:name="android.permission.INTERNET" /> gradle依赖(添加到build.gradle) implementation("com.

  • Retrofit和OkHttp如何实现Android网络缓存

    前提: 没做过网络缓存这方面的功能,所以想学习下.上网看了很多的文章,也看了部分视频.想把自己的一些小小的心德分享一下.如何能够稍微帮助到别人,那对我来说就算是有意义了.废话不多说了.进入正题. 1.网路请求 网络请求用的是Retrofit.用过的人,都知道优点.没用过的人就照着图示或者Demo去写就好了,而且网上的文章一大堆,本人就不赘述了. 网络请求的写法 2.添加缓存 重点来了,在网上看了许多的缓存方法.到最后还是选择了,OkHttp添加拦截器的这种方法.貌似用这种方法的人最多. 先来两张

  • Android中Retrofit的简要介绍

    Retrofit A type-safe HTTP client for Android and Java 适用于Java和Android的安全的HTTP客户端 Retrofit是一个可用于Android和Java的网络库,使用它可以简化我们的网络操作,提高效率和正确率.它将请求过程和底层代码封装起来只暴露我们业务中的请求和返回数据模型. public interface GitHubService { @GET("users/{user}/repos") Call<List&l

  • Android使用Retrofit上传文件功能

    本文实例为大家分享了Android使用Retrofit上传文件的具体代码,供大家参考,具体内容如下 一.封装RetrofitManager public class RetrofitManager {     private static RetrofitManager retrofitManager;          private Retrofit retrofit;     private RetrofitManager() {}     public static RetrofitMa

  • Android开发Retrofit源码分析

    目录 项目结构 retrofit 使用 Retrofit #create ServiceMethod #parseAnnotations HttpServiceMethod#parseAnnotations 第二种 非Kotlin协程情况 DefaultCallAdapterFactory#get 第一种 Kotlin协程情况 总结 项目结构 把源码 clone 下来 , 可以看到 retrofit 整体结构如下 图 http包目录下就是一些http协议常用接口 , 比如 请求方法 url ,

  • Android实例HandlerThread源码分析

    HandlerThread 简介: 我们知道Thread线程是一次性消费品,当Thread线程执行完一个耗时的任务之后,线程就会被自动销毁了.如果此时我又有一 个耗时任务需要执行,我们不得不重新创建线程去执行该耗时任务.然而,这样就存在一个性能问题:多次创建和销毁线程是很耗 系统资源的.为了解这种问题,我们可以自己构建一个循环线程Looper Thread,当有耗时任务投放到该循环线程中时,线程执行耗 时任务,执行完之后循环线程处于等待状态,直到下一个新的耗时任务被投放进来.这样一来就避免了多次

  • 浅谈Android的Lifecycle源码分析

    1. 简介 很早就听说了Google的Lifecycle组件,因为项目没有使用过,所以并没有过多的接触.不过最近看到了一篇文章,其中的一条评论提到了LiveData.恰巧这两天工作内容不多,所以赶紧研究一波! 不过在看LiveData之前,我觉得还是先看下Lifecycle吧(Lifecycle更像是LiveData的基础). 2. Lifecycle的简单介绍 Lifecycle的介绍,我们还是拿Google的官方文档作为参考吧. Lifecycle主要解决的是业务和Activity/Frag

  • Retrofit 源码分析初探

    现如今,Android开发中,网络层Retrofit+Okhttp组合好像已成标配,身为技术人员,这么火的框架当然得一探究竟,不为装逼,纯粹是为了充电而已. 基本使用介绍 介绍源码前,我们先看下Retrofit的基本使用,大致了解下流程,跟着这个流程来分析源码才不会乱. 1.初始化Retrofit对象 Retrofit retrofit = new Retrofit.Builder() //使用自定义的mGsonConverterFactory .addConverterFactory(Gson

  • Android LayoutInflater.inflate源码分析

    LayoutInflater.inflate源码详解 LayoutInflater的inflate方法相信大家都不陌生,在Fragment的onCreateView中或者在BaseAdapter的getView方法中我们都会经常用这个方法来实例化出我们需要的View. 假设我们有一个需要实例化的布局文件menu_item.xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" an

  • Android  LayoutInflater.inflate源码分析

    LayoutInflater.inflate源码详解 LayoutInflater的inflate方法相信大家都不陌生,在Fragment的onCreateView中或者在BaseAdapter的getView方法中我们都会经常用这个方法来实例化出我们需要的View. 假设我们有一个需要实例化的布局文件menu_item.xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" an

  • Android透明化和沉浸式状态栏实践及源码分析

    本文所提到的透明状态栏其实指的是将顶部的导航栏延伸到状态栏,使之浑然一体(Google官方建议状态栏颜色比导航栏的颜色略深一点),并不代表一定不设置背景色,比如导航栏是白色,则可设置状态栏为白色,视情况而定. 相比于iOS系统,Android系统对于状态栏的设置就显得稍微复杂了一点.Android系统提供了API 19以上对状态栏的设置接口,而直到API 23以上才提供对于icon颜色的设置,还有就是各家厂商(如魅族,小米等)对于状态栏的有自己的定制,对于需要使用浅色背景状态栏的应用,没处理好的

  • Android AsyncTask源码分析

    Android中只能在主线程中进行UI操作,如果是其它子线程,需要借助异步消息处理机制Handler.除此之外,还有个非常方便的AsyncTask类,这个类内部封装了Handler和线程池.本文先简要介绍AsyncTask的用法,然后分析具体实现. 基本用法 AsyncTask是一个抽象类,我们需要创建子类去继承它,并且重写一些方法.AsyncTask接受三个泛型参数: Params: 指定传给任务执行时的参数的类型 Progress: 指定后台任务执行时将任务进度返回给UI线程的参数类型 Re

  • Android入门之源码开发基础教程

    本文讲述了Android入门之源码开发基础教程.分享给大家供大家参考,具体如下: 下载 Android 源码之后,接下来就是学习或者进行开发. 在开发之前,谈一些开发必备知识或者工具,工欲善其事必先利其器嘛! 在前面一篇<Android入门之使用eclipse进行源码开发的方法>中基本上说了开发使用工具. 但是我们如何使用模拟器开发呢?! 当然你去删除或者增加app到模拟器就不可以按常规来操作了,花 5 -10 分钟了解一下,如果你有需要. 0. 编译源码 直接在下载的源码根目录下面,执行:

  • Android getJSONObject与optJSONObject的区别结合源码分析

    Android getJSONObject与optJSONObject的区别结合源码分析 json解析常见问题: getJSONObject与optJSONObject的区别,下面结合源码和案例来分析当我们使用这两周方法来解析数据时,哪种比较好. 源码分析: //使用getJSONObject时,如果返回的对象不是JSONObject,抛出JSONException异常 /** * Returns the value mapped by {@code name} if it exists and

随机推荐