它最终返回一个0bservable对象,这个过程会组织网络请求、解析响应结果、将响应结果发送给订阅0bservable的0bserver
这里我们需要拆成两步来看:loadServiceMethod()、invoke()分别做了什么。
2、网络请求的准备阶段
loadServiceMethod()完成的主要任务就是解析网络请求接口方法上的注解信息,得到数据适配器、数据解析器对象,最终封装一个CallAdapted继承了ServiceMethod的对象返回来,我们来一步一步看:
很显然,重点是parseAnnotations():
RequestFactory.parseAnnotations(retrofit, method)是重要的一步,它会去解析ApiService中对应方法上的注解信息、参数上的注解信息,准备网络请求的必要信息。
接下来又调用了HttpServiceMethod的parseAnnotations(),HttpServiceMethod继承了ServiceMethod:
上面讲到创建retrofit对象时设置了RxJava数据适配器、Gson解析器工厂,现在要从工厂中得到对应的数据适配器、解析器,最后将这些数据封装到CallAdapted里。
HttpServiceMethod还重写了ServiceMethod的invoke()方法:
它的adapt方法最终调用了RxJava数据适配器的adapt()方法:
至此,loadServiceMethod()方法的执行流程就结束了,最终返回的就是一个继承了HttpServiceMethod的CallAdapted对象。同时准备好了 OkHttpCall、数据适配器、以及数据解析器。
3、数据适配器 结合之前的分析,调用ServiceMethod的invoke()方法最终就是调用RxJava数据适配器的adapt()方法,参数就是OkHttpCall。
数据适配器对象是通过数据适配器工厂RxJava2CallAdapterFactory创建的:
所以adapt()方法会返回一个Observable对象,但还是太过粗略了,我们需要进一步探究该对象的奥秘。
按照上边的分析,应该先执行new CallExecuteObservable<>(call),得到responseObservable对象,再执行new BodyObservable<>(responseObservable),对其进一步封装,所以我们先看CallExecuteObservable类是如何实现的:
CallExecuteObservable类的核心就是subscribeActual()方法,当Observer订阅Observable时会执行该方法,即调用subscribe()方法时。 在subscribeActual()方法里会进行网络请求,并将结果传递给Observer。
那为什么BodyObservable类对responseObservable要进一步封装呢?去里边找找答案:
可以看到BodyObservable类的主要作用就是通过BodyObserver类增强我们自定义的observer功能,使其可以对CallExecuteObservable中observer.onNext(response)拿到的响应结果进一步处理,只取出响应体的数据发送给我们自定义的observer。
到这里数据适配器的主要任务就结束了,就是为整合RxJava做准备,调用Retrofit封装的OkHttpCall执行网络请求,并将结果发送给observer。
但还有些事情我们没搞清楚,那就是OkHttpCall,在CallExecuteObservable中执行它的call.execute()方法时,内部做了些什么,内部是如何通过OkHttp进行网络请求的。
4、OkHttp网络请求 OkHttpCall的execute()方法还是比较简单的:
所以OkHttpCall的execute()方法内部会构建OkHttp的Call对象,并来发起网络请求,但为什么是同步的请求呢?因为我们已经使用RxJava切换到子线程。这样Retrofit就和OkHttp关联上了。
5、数据解析器 OkHttpCall的parseResponse()的作用就是使用Gson将响应体的JSON字符串转换成指定对象。
 关键的就是responseConverter.convert(catchingBody),responseConverter就是通过配置Retrofit时设置的GsonConverterFactory数据解析器工厂得到的,对应的数据解析器就是GsonRequestBodyConverter:
terFactory数据解析器工厂得到的,对应的数据解析器就是GsonRequestBodyConverter:
云服务器ECS 第一篇:FTP文件服务器搭建目前打算将项目部署到云服务器上,并配置系统运行环境,搭建FTP服务器是系统部署的第一步,从这里开始!!!关于FTP:FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操
为什么80%的码农都做不了架构师?>>> ...
python中pandas是数据分析的利器,有两种基本的数据形式,Series、DataFrame两种,Series是单列的,DataFrame是平面的二维或者多维的。今天遇到一个问题,如何将两个dataFrame合并:总的来说有两种形式的合并:列名相同的合并,行名相同的合并列名相同的合并:append()函数,假设有如下数据。df = pd.DataFrame(np.random...
有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如 tomcat 中的 session。例如登录:用户登录后,我们把登录者的信息保存在服务端 session 中,并且给用户一个 cookie 值,记录对应的 session。然后下次请求,用户携带 cookie 值来,我们就能识别到对应 session,从而找到用户的信息。
Python PyQt5 调试窗口显示
JUCjava.util.concurrent的缩写线程的6种状态创建,可运行,阻塞,等待,计时等待,终结Lambda表达式java1.8之后允许接口中有部分方法的实现,需要用default关键字描述方法@FunctionalInterface 注解表示函数式接口(仅有一个抽象方法)常见异常总结ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常StackOverflowError:多线程案例
一、基本配置elasticsearch的config文件夹里面有两个配置文 件:elasticsearch.yml和logging.yml,第一个是es的基本配置文件,第二个是日志配置文件,es也是使用log4j来记录日 志的,所以logging.yml里的设置按普通log4j配置文件来设置就行了。下面主要讲解下elasticsearch.yml这个文件中可配置的东西。cluster.na
MyBatis中传参时为什么要用#{} MyBatis中传参时为什么要用#{},这个问题和MyBatis如何防止SQL注入类似。不过在解释这个问题之前,先解释一下什么是SQL注入,还有些称作注入攻击这个问题。 SQL注入就是SQL对传入参数的拼接。sql语句是String类型的,如果用+来拼接,表示的是直接操作这个String类型的字符串,这是改变了sql的具体内容了,如果用#{id},表示的是操作字改变里面字段的参数值。例如:用+拼接的:"select*fromu...
【问题描述】“蚂蚁庄园”的小鸡拍球游戏中,有三种可能的得分:5分、8分和10分。现从键盘输入一个整数的得分值,请输出该局游戏可能的得分组合。【输入形式】输入只有一行,包括一个正整数n。【输出形式】输出可能有若干行,每行是一种得分的序列,包括得5分的次数、得8分和得10分的次数,前导符和次数之间用英文冒号分隔,相邻得分次数之间用一个空格分隔。【样例输入】40【样例输出】5:0 8:0 1...
因为colab是域外的服务器,所以在国内想要上传数据集,速度是非常非常的慢,因此写下自己在解决问题时的一些方法。通过将数据集传到域外的一款软件,然后数据集传到colab我用的方法是先将数据集传到onedrive上面(放心传数据集到onedrive上面是很快的),然后将数据集通过onedrive传到谷歌云盘,然后将谷歌云盘上的数据集传到colab上。听起来很麻烦,其实很简单。第一步:登录到onedrive,然后将数据集传到文档这个文件夹下面,直接拉进去就行,必须传到文档才能进行我下面的操作。第二步
Ubuntu16.04搭建rust开发环境安装vscode进入vscode官网下载Linux下的安装包,使用dpkg命令安装sudo dpkg -i code_1.37.0-1565227985_amd64.deb等待安装完成,搜索vs可以直接找到,为了方便,将其添加到启动器。如果不习惯英文,可以对vscode进行汉化,打开vscode,快捷键Shift + Ctrl + P,输入Configure Display Language进行安装即可,安装完毕需要重启vscode。安装rus
1、需求描述v-1需求:用户给予一个整数vector,我们必须返回一个新的vector,其中内含原vector之中小于10的所有数据。根据这个需求可以很容易的设计一个如下的函数 v1_less_than_10():using vecInt = vector<int>;vecInt v1_less_than_10(const vecInt& vec){ vecInt nVec; for (size_t ix = 0; ix < vec.size(); ix++