文档章节

Retrofit源码分析

街角的小丑
 街角的小丑
发布于 2017/09/11 16:06
字数 1369
阅读 14
收藏 0

前言

    第一次接触retrofit的时候还是个菜鸟(现在也是),使用一套规则定义一个接口,没有实现,结果竟然能够顺利完成和okhttp的对接。于是想要了解一下它的实现原理。

    本文仅是简单的源码分析,在读本文之前,或许应该先读一下下面这篇文章:

https://my.oschina.net/zzxzzg/blog/993685

Retrofit.Build

    Retrofit总是从一个Build开始,我们会在这个build中进行一些全局性的设置,比如baseUrl,Converter,CallAdapter,okhttpclient等。

    所以Retrofit.Build.build()功能并不复杂,保存设置的项目,创建一个真正 的Retrofit对象,不过其实还是有一些值得注意的

  1.     设置了一个默认的callbackExecutor(方法回调的线程执行器),就会使用默认的,而在Android平台中,默认就是主线程中执行,通过一个叫做MainThreadExecutor的类。
  2. 无论是否添加了自己的CallAdapter,都会添加一个默认的CallAdapter,而在android中,就是类ExecutorCallAdapterFactory.

    注:    CallAdapter 就是将返回的Call类型进行封装的一个适配器,Converter是对返回的ResponseBody进行封装处理的适配器。

Retrofit.create

    Retrofit所有神奇的起源,我们通过调用该方法,将一个接口变成了一个可以调用的类。

    实际上使用的原理就是Proxy代理:

 public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    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, @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);
            }
            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);
          }
        });
  }

    首先是eagerlyValidateMethods方法,将service中的所有方法封装成一个ServiceMethod对象,并存储起来。至于ServiceMethod是什么,接下去再看。

    然后就返回了一个ProxyInstance,当我们调用定义的接口中的方法时,就会转而调用invoke方法。

    invoke方法的工作其实就是删选出该方法是否是接口中定义的,如果是,那么获取该方法的servicemethod,然后创建一个okhttpcall(请求结果回调)。最后再将okhttpcall用适当的calladapter(见上)进行封装后返回。

ExecutorCallAdapterFactory     ExecutorCallbackCall

    CallAdapter.Factory 声明了一个get的接口,就是根据返回类型和注解(你在接口中声明的某个方法的返回类型,和方法的注解)生产一个CallAdapter(每个方法都会生成一个CallAdapter).

    而CallAdapter实际上之前有说过,就是将源返回值(Call<?>)进行封装的一个适配器类,通过调用方法adapt进行封装。

    知道这两个后,那么久看下Androir默认一定会提供的ExecutorCallAdapterFactory,这个东西的get方法很简单,只要返回类型是Call的,都匹配,并返回一个CallAdapter。这个CallAdapter的adapt方法返回一个ExecutorCallbackCall类型对象,继承与call,它的作用非常简单直接,将所有call中的回调方法迁移到指定的线程。(而Android中默认指定了主线程。)

OKHttpCall

    对于okhttp的使用这里我们不做介绍,我们知道okhttp总是会有大概如下的调用

    Call call = client.newCall(request);

    call.enqueue(CallBack ...)

    call.execute

    通过request产生一个call,然后在该call上进行同步或者异步的请求。而retrofit的okhttpcall也是采用同样的接口。

    我们在retrofit.create中已经介绍了,我们通过一个servicemethod和对应的参数来生成一个okhttpcall,然后将这个call在传给对应的calldapter进行一次封装,等待触发enqueue或者execute(不同的calladapter封装成不同的类型,rxjava2calladapter或者之前的ExecutorCallbackCall等,触发方式不同,但是本质上就是调用call的这两个方法。)    

    我们已enqueue为例(execute其实一样),首先通过调用createRawCall方法来生成一个call。

 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中的 toRequest方法生成request,然后调用callFactory的newCall(callFactory就是我们设置的okhttpclient或者默认的new OkhttpClient)。

    生成call以后,就通过在这个call上调用enqueue进行请求,并且注册回调。回调的onResponse方法中,我们会对response进行一次解析,通过方法parseResponse。该方法实现有些复杂,但是功能很清晰,就是将okhttp的response包装成retrofit自己提供的Response对象(converter的body解析也是在这里进行调用的,具体就是调用了serviceMethod的toResponse的方法)。

ServiceMethod

   同上上述分析,我们发现ServiceMethod承载的最主要的功能就是toRequest方法,生成一个request(当然也有toResponse来进行解析,但是其实代码很简单)。

   如果你觉得我会详细去分析这个东西,那么你就错了,不妨亲自打开代码,看看build方法和toRequest方法在干嘛。其中已经并不涉及到架构问题,虽然不一定简单,甚至说是复杂,但是至少我们知道它做的就是通过解析我们定义时使用的注解,将他和传入的参数进行合并,生成request的过程。

总结

    retrofit代码的原理并不复杂,但是在笔者看来,算得上是adapter界的楷模,在适配器的使用上非常规范标准,值得借鉴。 

© 著作权归作者所有

共有 人打赏支持
街角的小丑
粉丝 1
博文 92
码字总数 149517
作品 0
杭州
Android网络框架

Android OKHttp3.0 以上使用方法 Android OKHttp3.0 以上使用方法详解 Retrofit 之日志拦截 Retrofit 日志拦截相关介绍 Retrofit源码解析 Retrofit的源码分析将从基本的使用方法入手,分析r...

掘金官方
2017/12/12
0
0
Retrofit源码分析

关于Retrofit的使用这里就不再赘述了,还不太了解Retrofit使用的同学 Retrofit简介 今天我们来聊一聊Retrofit的内部实现,通过源码来分析Retrofit的整个执行顺序。 在没有框架的时候,做一次...

乐小文
2017/04/09
0
0
第三方开源库 Retrofit - 源码设计模式分析

Retrofit 这个开源库对我成长还是挺大的,自己虽不常用,但他的源码封装思想,却需要用到实际的开发中。这些年有两本书一直都在看 《Android的源码》和《 JakeWharton的源码》。JakeWharton...

红橙Darren
2017/12/15
0
0
网络库Retrofit2原理简析

之前我们分析过了Okhttp这个优秀的网络请求库,但是在实际的使用时,还是会觉得有很多的不方便,你会发现它跟HttpUrlConnection,或者HttpClient一样,是一个比较底层的网络请求库,处理的是...

Ihesong
2017/12/11
0
0
Retrofit2.0- 源码分析

1. 阅读引导 在分析 Retrofit 源码之前,你首先得理解动态代理模式,因为Retrofit是通过动态代理的方式进行统一网络请求接口类的处理。Retrofit的代码量并不大,只是对OkHttp进行了封装,用更...

负了时光不负卿
2017/12/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

C++ std::function 和 std::bind

C++11提供了std::function和std::bind两个工具,用于引用可调用对象。这些可调用对象包括 普通函数,Lambda表达式,类的静态成员函数,非静态成员函数以及仿函数等。引用可调用对象,可以用于...

yepanl
40分钟前
0
0
python:可迭代对象的索引

关于 python的range的用法: 注意是[ 开始,结束)的半开区间,不包括结束 http://www.runoob.com/python/python-func-range.html import collectionsfrom collections import Iterable字符串......

Oh_really
55分钟前
2
0
docker-compose ,docker-stack

1.例子 version: "3"services: php: image: registry.cn-hangzhou.aliyuncs.com/lxepoo/apache-php5 ports: - "38080:80" networks: - my_php_mysql volum......

chenbaojun
今天
3
0
SQL_Server2000示例数据库NorthWind的分析(转)

SQL_Server2000示例数据库NorthWind的分析 表名:Categories(食品类别表) 表结构: 字段名称 数据类型 长度 允许为空 CategoryID(主键) int 4 否 CategoryName nvarchar 15 否 Description ...

QQZZFT
今天
1
0
laravel 5.5 Session store not set on request.

laravel 5.5 数据存入session,会出现Session store not set on request.错误。查了下laravel 5.5将session放到global middleware中,需要laravel的文件 ./app/Http/Kernel.php中的加上一句:...

MichaelShu
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部