2016-05-06 16:07:09

1.先上一张Retrofit的代码结构图:

可以看到,Retrofit自身的结构很简单,代码量也不是很大。红色框部分是一些注解类,就是一些标记。

简单的看一下客户端是如何使用Retrofit的:

定义接口:

 public interface WeatherDataService {
@GET("/wtr-v2/temp/realtime")
Call<MiWeatherData> getMiWeather(@Query("cityId") String cityId); @GET("/wtr-v2/temp/realtime")
Observable<MiWeatherData> getMiWeatherObservable(@Query("cityId") String cityId); @GET("/wtr-v2/temp/realtime")
MiWeatherData getMiWeatherCustomCallAdapter(@Query("cityId") String cityId);
}

客户端调用:

     private void getWeather() {
retrofit = new Retrofit.Builder()
.baseUrl("http://weatherapi.market.xiaomi.com")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
service = retrofit.create(WeatherDataService.class);
Call<MiWeatherData> result = service.getMiWeather("101010100"); try {
Response<MiWeatherData> r = result.execute();
MiWeatherData data = r.body();
Log.e("David", "ResponseBody data = " + data);
if (data != null) {
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.SD);
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.cityid);
Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.WS);
}
} catch (IOException e) {
e.printStackTrace();
}
}

2. 几个主要类的UML简图:

2.1 Retrofit和Retrofit.Factory

Retrofit和ServiceMethod使用了Builder模式(省略了Director和Abstract Product的Builder模式)来构建自己,Retrofit的作用很简单,传入需要的参数,构建一个Retrofit对象,然后通过动态代理的方式,得到我们自定义的方法接口的实例,参数中除了baseUrl之外,其他都是可选的,如果没设置会使用默认值。

ServiceMethod就是我们自己调用的方法做一层封装而已,包括解析方法使用的注解、参数等,同时提供方法,生成网络请求需要的Request和解析请求结果。

2.1 CallAdapter和CallAdapter.Factory

CallAdapt的作用是把Call转变成你想要返回的对象,起作用的是adapt方法,CallAdapter.Factory的作用是获取CallAdapter。ExecutorCallAdapterFactory的CallAdapter会将回调方法放到主线程中执行,DefaultCallAdapterFactory不是。两者的CallAdapter能够接受的返回值类型为Call<T>。很明显,RxJavaCallAdapterFactory的CallAdapter能够接受的返回值是Oservable<T>。如果想让的方法直接返回一个对象,可以自定义一个CallAdapter.Factory。代码如下:

 private class MyCallAdapterFactory extends CallAdapter.Factory {
@Override
public CallAdapter<?> get(final Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new CallAdapter<Object>() {
@Override
public Type responseType() {
return returnType;
} @Override
public <R> Object adapt(Call<R> call) {
try {
return call.execute().body();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
};
}
}

Service方法和CallAdapter的对应关系如下:

2.3 Converter和Converter.Factory

Converter的作用是将网络请求结果ResponseBody转换为我们希望的返回值类型。Converter.Factory的作用是获取Converter,这里很明显采用了静态工厂模式。如果你不设置ConverterFactory,那么调用WeatherDataInterface的三个方法都会崩溃,提示:Could not locate ResponseBody converter for class MiWeatherData。这是因为使用了默认的BuiltInConverters,而我们的方法不满足获取到responseBodyConverter的要求,所以崩溃,代码截图如下:

所以,如果不想设置Converter,那么我们的方法返回值必须为ResponseBody或者Void,如果是ResponseBody,且有@Streaming注解,会使用StreamingResponseBodyConverter,否则使用BufferingResponseBodyConveter。这两者基本都是原封不动的返回ResponseBody。而VoidResponseBodyConverter返回null~感觉这点比较坑,干点什么不好,非要返回null

Retrofit提供了多个Converter供选择,比如将Json转换为Object的GsonConverterFactory,如下图:

这也是Retrofit的一大特点---足够的开放、灵活。

2.4 OkHttpCall

OkHttpCall继承自interface Call,主要的作用是调起执行网络请求以及返回当前请求状态状态,但是真正的网络请求其实在okhttp3.Call接口,接口定义如下:

这个接口的实现类是okhttp3.RealCall,可以发现,Retrofit的Call接口和okhttp3的Call接口定义几乎是完全一样的,目的当然是实现OCP,这样做的好处显而易见:

1.利于扩展,retrofit2.Call接口可以有其他的实现类,不一定非要用OkHttp,只不过OkHttpCall用的恰好是OkHttp而已。

2.解耦,为了实现第一个目的,retrofit2.Call接口的存在就是理所当然的。

2.5 ParameterHandler

这是一个辅助类,用于解析我们自己定义的Method,由于我们是通过注解的方式来表达各种信息,比如请求类型(POST、GET)、Query参数、Body等,因此需要解析出来。不在主线,因此不作分析,但是里面的实现蛮复杂的,是个细致活儿。

2.6 RxJavaCallAdapterFactory分析

CallAdapterFactory的作用及工作机理前面已经介绍过了,RxJavaCallAdapterFactory的作用也是一样的,只不过RxJavaCallAdapterFactory中内部又定义了三种CallAdapter:ResponseCallAdapter、ResultCallAdapter和SimpleCallAdapter,根据返回值类型决定到底使用哪个,代码如下:

本质上处理流程是一致的,都是按照RxJava的套路执行请求并处理返回值的。

关于Retrofit中主要类的分解到此结束,之所以这么繁琐的画UML图,目的是为了更加深入的了解作者设计类的思路,比如作者是如何考虑一个类的功能、边界在哪里等。

第一篇:Retrofit主要类UML图的更多相关文章

  1. 【面试 JDK】【第一篇】Object类面试详解

    1.Object类有哪些方法 1>clone()方法 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异 ...

  2. 如何制作一款HTML5 RPG游戏引擎——第一篇,地图类的实现

    一,话说天下大事 前不久看到lufy的博客上,有一位朋友想要一个RPG游戏引擎,出于兴趣准备动手做一做.由于我研究lufylegend有一段时间了,对它有一定的依赖性,因此就准备将这个引擎基于lufy ...

  3. 关于ER图和UML图之间的对比

    ER图与UML图 ER图:实体-联系图(Entity-Relation Diagram)用来建立数据模型,在数据库系统概论中属于概念设计阶段,ER图提供了表示实体(即数据对象).属性和联系的方法,用来 ...

  4. java 线程池第一篇 之 ThreadPoolExcutor

    一:什么是线程池? java 线程池是将大量的线程集中管理的类,包括对线程的创建,资源的管理,线程生命周期的管理.当系统中存在大量的异步任务的时候就考虑使用java线程池管理所有的线程.减少系统资源的 ...

  5. UML图学习之二 类图

    类图(ClassDiagrams)是根据系统中的类以及各类之间的关系描述系统的静态视图.类图不仅显示系统内信息的结构,还描述系统内这些信息的行为.类图的一个重要目的是为其他图(如顺序图.交互图)定义一 ...

  6. eclipse下生成Java类图和时序图,生成UML图

    1.安装和使用AmaterasUML 安装AmaterasUML前,需要先安装GEF采用eclipse在线安装方式安装就好.eclipse在线安装GEF的地址:http://download.ecli ...

  7. java 类与类之间的关系 及uml图

    类与接口之间的关系 : 继承 类与类之间的关系 :继承关系  包含关系 类与对象之间的关系 : 实例 UML 类图中类与类之间的关系: 泛化关系(generalization) 关联关系(associ ...

  8. C++第一篇--类的引入

    C++第一篇--类的引入 1. 用C语言输出两个人的信息 Person1.c:通过字符实现 #include <stdio.h> int main(int argc,int **argv) ...

  9. UML图类,接口之间的关系

    UML图类之间的关系(来自大话设计模式中的一张图,代表了类,接口之间的各种关系)

随机推荐

  1. xcopy中提示“无效的参数数量”的解决方法

    原因是DOS下不支持长文件名,只支持8.3格式的文件名 .如果是Windows下的命令行,对于有空格的命令行要加引号.应该是 copy "c:\program files" &qu ...

  2. 公共交通3D指纹验证系统解决方案

    为了响应国家关于老年人的优待政策,华本研发了退休老人乘公交车指纹认证系统.指纹认证系统不仅方便老人乘坐公交,还能为公共部门减压,杜绝伪造优待证乘坐公交的不法行为. 目前,优待证都是人工检查,缺乏有效的 ...

  3. 新课程开始的第二天,HTML基础制作

    天正式开始学习HTML的基础制作,有简单的指令开始入手. 第一天的学习,因为基础,所以觉得还算简单,主要是对网页背景.图片.文字.表格等的编辑,和一部分链接的使用. 由下面的的一个事例,通过所学的简单 ...

  4. ABAP开发顾问必备:SAP ABAP开发技术总结

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  5. 【解决方法】magento paypal快速结账 不跳转

    magento paypal Express Checkout(快速结账) 页面不跳转到Paypal的解放方法 我使用的magento 1.9.0.1 版本的,Paypal 快速结账都已经设置完毕,但 ...

  6. PHP Mysqli 数据库连接

    ---恢复内容开始--- $connection=new mysqli($db_host,$db_user,$db_password,$db_name);if(!mysqli_connect_errn ...

  7. python-05

    首先是安装工具 Linux 安装mysql:mysql-server 安装python-mysql模块: python-mysqldb Windows 下载安装mysql python操作mysql模 ...

  8. laravel 实现上传 excel

    //导入电话号码 public function postTel(){ set_time_limit(0); ini_set('memory_limit','1024M'); $params = In ...

  9. 数据挖掘算法(四)Apriori算法

    参考文献: 关联分析之Apriori算法

  10. ExtJS自制表格Grid分页条

    试过Grid自带的load和分页功能,没有成功,干脆就自己写了...... 主要是查询条件比较复杂...... 希望哪位大神能有更好的意见. Ext.define('MyApp.ux.Paginati ...