Retrofit是Square公司开发的一个类型安全的Java和Android 的REST客户端库,这个库为网络认证、API请求以及用OkHttp发送网络请求提供了强大的框架 。Retrofit 库使得从web api下载JSON 或者xml数据变的非常简单直接,一旦数据下载完成即将其解析成普通java类(POJO)。
Retrofit支持Java 7 或 Android 2.3及以上版本。
注:Rest API是一种软件设计风格,服务器作为资源存放地。客户端去请求GET,PUT, POST,DELETE资源。并且是无状态的,没有session的参与。
Retrofit使用的最核心的两个技术:动态代理和Java反射。Retrofit非常巧妙的用注解来描述一个HTTP请求,将一个HTTP请求抽象成一个Java接口,然后用了Java动态代理的方式,动态的将这个接口的注解“翻译”成一个HTTP请求,最后再执行这个HTTP请求。
Retrofit无非就是让用户创建接口,并在接口中指定网络访问路径、规则,把接口传入Retrofit,Retrofit进行层层解析,然后调用OkHttp完成实际的网络请求并将请求结果处理后返回给用户。
底层使用OkHttp进行网络传输,性能好,速度快;
拥有出色的API文档和社区支持
可以自动将REST API返回的数据转化为Java对象,且支持多种数据转换格式(如json、xml等)
使用Java注解声明HTTP请求
支持 Multipart请求和文件上传
下面通过一个实际的例子介绍Retrofit的使用流程。该示例程序通过使用Retrofit向https://api.github.com/ 获取指定github用户的相关信息。目前Retrofit的最新版本为2.0版,与此前的1.9有比较大的不同,该示例代码是基于Retrofit2.0实现的。
注:在浏览器输入网址https://api.github.com/users/"想要查询的github用户名",服务器便会返回一个包含该用户信息的json字符串,如输入https://api.github.com/users/littleshuang ,所得到的json字符串为
第一步:添加依赖(gradle)
//retrofit底层网络框架为OkHttp,所以必须添加OkHttp的依赖包 compile 'com.squareup.okhttp3:okhttp:3.2.0' //retrofit的依赖包 compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' //添加了一个官方提供的json conventer compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
第二步:构建返回数据对应的实体类
注:Retrofit可以自动根据我们提供的conventer将返回数据转化为JOPO,所以我们需要创建一个返回数据的实体类
本实例中根据前述json数据格式创建了一个User类
第三步:定义一个请求数据的接口,该接口中包含用于请求数据的方法定义(此例中定义了一个名为ServiceInterface的接口,其中包含一个获取用户信息的get请求)
@GET:retrofit提供的一个用于定义请求方法的注解,retrofit会根据该注解将该方法解析为一个相应请求类型的http请求
users/{user}:http请求的相对路径,该路径为相对于自定义的BaseURL的路径,该示例中的BaseURL为:https://api.github.com/ ;大括号包裹的{user}是retrofit提供的一种动态生成URL地址的方式,大括号中包含的内容的具体类型和数据需要通过注解@Path后面的参数获得,此例中为一个String类型变量,具体值由user变量提供
注:此处也可以使用绝对路径,但一般来说,同一项目中的绝大部分网络请求都是基于同一服务器基址,变化的只是后面的相对路径,所以推荐使用BaseURL + 相对路径的方式,这种方式既能减少不必要的冗余代码,使代码更加简洁,又能减少出错概率、提高重构效率。
Call<T>:retrofit中定义的一个接口,该接口中主要定义了同步请求(execute)、异步请求(enqueue)、取消请求(cancle)等方法,该接口的实现类通过实现这些方法执行具体的网络请求操作;虽然Retrofit默认使用OkHttp执行具体的网络请求操作,但是,我们可以通过自己实现该接口而采用自己的逻辑来执行网络请求,这种方式非常插件化,从而非常灵活
第四步:使用Retrofit对象执行网络请求
// 获取一个Retrofit对象,并设置该对象的BaseURL和conventer Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .build(); // service实际上是create方法返回的一个ServiceInterface接口的动态代理 ServiceInterface service = retrofit.create(ServiceInterface.class); // 通过下面这个语句就创建了一个向获取数据的get请求 Call<User> call = service.getUser("littleshuang"); // enqueue是一个异步请求方法 call.enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { if (response.isSuccess()){ // isSuccess()函数的处理逻辑非常简单,只是判断了下response的返回码是否为200,是即true,否则false // 所以可以自己根据自己的需要进行处理 User user = response.body(); if (user != null){ etRetrofitGetUser.setText("User login: " + user.getLogin()); } } } @Override public void onFailure(Call<User> call, Throwable t) { etRetrofitGetUser.setText("Sth wrong!"); } });
结果展示:左右两图分别展示的是网络请求成功和失败两种情况下的结果
Retrofit源码下面的http包中包含了Retrofit中定义的全部22中注解类型,这些注解都是用于控制HTTP请求的一些接口方法,下面对这些注解进行简单的介绍,便于以后的使用
请求方法类:@GET @HEAD @POST @DELETE @PUT @OPTIONS @PATCH,这几个注解分别表示定义一个get、head、post、delete、put、options或patch请求;
HTTP请求体:@BODY,该注解适用于在使用post或put请求时想要直接控制HTTP请求体的情况,此注解参数不能为空;
定义一个表单形式的请求:@FormUrlEncoded及@Field(或@FieldMap),该注解适用于需要使用表单形式提交一个名值对的表单数据的情形,@FormUrlEncoded声明该请求的请求体为表单形式,@Field定义请求体中的一组名值对,而@FieldMap定义多个名值对的组合
For example:
@FormUrlEncoded @POST("users/{user}") User updateUser(@Field("id") int id, @Field("name") String name); @FormUrlEncoded @POST("users/") Call<User> add(@FieldMap Map<String, String> fields);
使用 service.updateUser(1, "Bob")时,请求体为id=1&name=Bob
使用service.add("name", "Bob", "nickname", "LittleBob")时,请求体为name=Bob&nickname=LittleBob
HTTP请求头:@HEADER 和@HEADERS,注意这两者的区别,两者均可以用于定义请求头部信息,但是前者会覆盖之前定义的头部信息,而后者不会,只会在后面进行追加;所以当多次对同一名称的头域进行赋值时,使用前者只会保留最后一次的赋值,即一个头域至多只有一个赋值,而使用后者则会保留所有的赋值,即一个头域对应多个取值;
自定义HTTP请求客户端:@HTTP
定义一个Multi-part类型的请求:@Multipart和@Part(或@PartMap),该注解适用于请求体为Multi-part类型的请求,@Multipart声明一个Multi-part类型的请求,@Part定义一个Multi-part类型请求的一个单一部分,@PartMap定义一个一个Multi-part类型请求的名值对,用法类似于表单形式的请求的用法,就不详细介绍了
@Path:该注解后面的参数用于替换url中{}包含的部分内容
查询参数:@Query和@QueryMap分别定义一个查询参数和一个查询参数键值对
@Streaming:定义该注解表示将请求方法的返回值直接以流的形式返回,而不解析为Java实体类
@Url:该Url是一个相对于BaseURL的一个路径,定义该参数就表示该请求方法的相对地址为参数后面的内容
Retrofit和OkHttp同属于Square公司的开源项目,这两者是互补的关系,OkHttp是一个实现了HTTP协议的客户端,类似于HttpClient,而Retrofit是一个基于OkHttp的封装库,该库主要简化了http请求的实现过程,使得开发者只需关注自身功能的实现,而不必书写那些比较冗余的代码。但也正是由于Retrofit的高度封装性,其扩展性就相对比较弱,某些比较灵活的功能还需要开发者自己通过OkHttp来实现。
Retrofit和Volley两者均是目前比较受开发者喜欢的两个网络库,不过这两者还是有比较大的差异。
Retrofit的底层实现是OkHttp,Volley的底层实现的是HttpClient和HttpUrlConnection;
Retrofit的返回可以自动解析为Java实体类,而Volley的返回数据类型根据请求类型而定(StringRequeset、ImageRequest、JsonObjectRequest或JsonArrayRequest),同时需要自己进行解析;
Retrofit拥有比较详细的API文档和比较活跃的社区支持,而google貌似并未给Volley提供开发文档,只是在Android developers中的网络部分有所提及,所以在易用性方面,感觉Retrofit更胜一筹;
Retrofit支持动态生成URL,Volley好像并不支持;
两者均异步请求方式,这在Android应用中是非常重要的,因为Android程序中不允许在Home线程中执行网络操作;