当前位置:首页 > 谈天说地 > 正文内容

Android开发Retrofit源码分析

34资源网2022年07月28日 11:01266

项目结构

把源码 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源码分析的资料请关注萬仟网其它相关文章!

看完文章,还可以用支付宝扫描下面的二维码领取一个支付宝红包,目前可领1-88元不等

支付宝红包二维码

除了扫码可以领取之外,大家还可以(复制 720087999 打开✔支付宝✔去搜索, h`o`n.g.包哪里来,动动手指就能领)。

看下图所示是好多参与这次活动领取红包的朋友:

支付宝红包

扫描二维码推送至手机访问。

版权声明:本文由34楼发布,如需转载请注明出处。

本文链接:https://www.34l.com/post/19938.html

分享给朋友:

相关文章

100元内最好的音箱选择哪种好?看看这款适合你不?
100元内最好的音箱选择哪种好?看看这款适合你不?

目前市面上的音箱种类繁多,有的音质非常好,有的音质比较差,有些朋友酷爱音乐,可是又不想花太多钱在这些音箱上面,一般都会选择一些100元以内的音箱。那么100元内最好的音箱选择哪种好?下面,小编给大家推荐一款迷你型的小音箱,大家一起来看看吧。...

带货直播运营怎么做(直播公司盈利模式)
带货直播运营怎么做(直播公司盈利模式)

直播网红千千万,谁能争当NO.1?随着直播崛起,越来越多的人想要入场分一杯羹,BUT,80%的人都不懂直播运营的内容法则。那么,新手主播怎么玩才能快速脱颖而出呢?掌握这四大直播运营的内容规则,人气轻松翻倍!1. 直播内容多样化主播想要保证直...

逍遥手机模拟器怎么用(逍遥安卓模拟器详细使用教程)
逍遥手机模拟器怎么用(逍遥安卓模拟器详细使用教程)

真正的5V5公平竞技对战,传承端游纯正体验。人气英雄,经典还原;公平竞技,实力至上;峡谷传说,掌心再现。策略、战术、意识、配合,在移动端重现峡谷战场乐趣。 为了庆祝大家期待已久的中国区开服,官方也带来了五大福利活动,用户可免费参与,并获...

联想新手机什么时候上市(联想2021即将上市新款笔记本)
联想新手机什么时候上市(联想2021即将上市新款笔记本)

11月8日,联想中国区手机业务部总经理发布了一则新机预告:摩托罗拉edge X的发布已进入倒计时阶段,在骁龙898处理器即将发布之际预告新机,很大可能预示着首发权已到手。而在双十一当天,陈劲又发布了一则微博,暗示摩托罗拉的全新手机已到手,“...

融资丨「PPIO边缘云」完成亿元A1轮融资,刷新边缘云领域融资记录
融资丨「PPIO边缘云」完成亿元A1轮融资,刷新边缘云领域融资记录

创业邦获悉,近日,边缘云公司PPIO宣布完成过亿元A1轮融资,由创世伙伴、张江科投、磐霖资本等多家机构联合投资,Pre-A轮投资方蓝驰创投、沸点资本及华业天成继续追加投资,光源资本担任融资财务顾问。这是公司半年内再次获投资人支持,公司A2...

一场关于元宇宙公司之死的剧本杀
一场关于元宇宙公司之死的剧本杀

编者按:本文来自脑极体,创业邦经授权发布。 2021年,被称作元宇宙元年。这种结合了区块链、虚拟现实、增强现实多种技术的概念,据称能够提供社交、娱乐、电商多种功能。美国彭博社称,元宇宙的市场规模将在2024年将达到8000亿美元。而就在2...