原帖地址:http://blog.csdn.net/carson_ho/article/details/73732076 学习Retrofit比较好的教程
Retrofit是什么
A type-safe HTTP client for Android and Java
Retrofit是这样介绍Retrofit的,简单的来说Retrofit是一个Http请求的框架,和Google开发的Volley功能上非常相似,但是Retrofit使用起来更加方便,Retrofit的设计也更加合理
Retrofit有什么优点
- Retrofit依赖于okHttp,需要集成okHttp
- Retrofit通过注解配置网络请求参数
- 支持同步/异步的请求
- 提供对RxJava支持
Retrofit是一个Restful的HTTP网络请求框架的封装,因为网络请求的工作本质上是OkHttp完成,而Retrofit仅仅是负责对网络请求接口的封装,App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数、Header、URL等信息,之后由OkHttp完成后续的请求操作。
在服务端返回数据后,OkHttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析
Retrofit怎么用
1.添加依赖(gradle)
在modul的build文件下的dependencies中添加配置 此处使用Retrofit2
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
权限添加
<uses-permission android:name="android.permission.INTERNET"/
2.创建接收服务器返回数据的类
3.创建用于描述网络请求的接口
- Retrofit将Http请求抽象成Java接口:采用注解描述网络请求参数和配置网络请求参数
- 用动态代理动态将该接口的"注解"翻译成一个Http请求,最后再执行Http请求
- 接口中的每个方法的参数都需要使用注解标注
注解类型
第一类 网络请求方法
- @GET @POST @PUT @DELETE @HEAD 分别对应HTTP中的网络请求方式
public interface GetRequest_Interface {
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation> getCall();
// @GET注解的作用:采用Get方法发送网络请求
// getCall() = 接收网络请求数据的方法
// 其中返回类型为Call<*>,*是接收数据的类(即上面定义的Translation类)
}
- Retrofit把网络请求的URL分成了两部分设置
//第1部分 在网络请求接口的注解设置
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation> getCall()
//第2部分 在创建Retrofit实例时通过.baseUrl()设置
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/") //设置网络请求的Url地址
.addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
.build();
- 一个请求的URL可以通过替换块和请求方法的参数来进行动态的URL更新,替换块是由被{}包裹起来的字符串构成
Retrofit网络请求的完整URL具体整合规则
- @HTTP
- 作用:替换@GET、@POST、@PUT、@DELETE、@HEAD注解的作用 及 更多功能拓展
- 具体使用:通过属性method、path、hasBody进行设置
public interface GetRequest_Interface {
/**
* method:网络请求的方法(区分大小写)
* path:网络请求地址路径
* hasBody:是否有请求体
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getCall(@Path("id") int id);
// {id} 表示是一个变量
// method 的值 retrofit 不会做处理,所以要自行保证准确
}
第二类标记
a. @FormUrlEncoded
- 作用:表示发送form-encoded的数据
每个键值对需要用@Filed来注解键名,随后的对象需要提供值
b. @Multipart
- 作用:表示发送form-encoded的数据(适用于文件上传的场景)
每个键值对要用@Part来注解键名,随后的对象需要提供值
public interface GetRequest_Interface {
/**
*表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
/**
* {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
* 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
}
// 具体使用
GetRequest_Interface service = retrofit.create(GetRequest_Interface.class);
// @FormUrlEncoded
Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
// @Multipart
RequestBody name = RequestBody.create(textType, "Carson");
RequestBody age = RequestBody.create(textType, "24");
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);
第三类 网络请求参数
a. @Header & @ Headers
- 作用:添加请求头&添加不固定的请求头
// @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()
// 以上的效果是一致的。
// 区别在于使用场景和使用方式
// 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
// 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法
b.@Body
- 作用:以Post方式传递自定义数据类型给服务器
- 注意:如果提交的是一个Map,作用相当于@Field
c.@Field&@FieldMap
*作用:发送Post请求时提交请求的表单字段
*与@FromUrlEncoded注解配合使用、
public interface GetRequest_Interface {
/**
*表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
/**
* Map的key作为表单的键
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);
}
// 具体使用
// @Field
Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
// @FieldMap
// 实现的效果与上面相同,但要传入Map
Map<String, Object> map = new HashMap<>();
map.put("username", "Carson");
map.put("age", 24);
Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
d @Part&@PartMap
- 作用:发送Post请求时提交请求的表单字段
与Field功能相同,但携带的参数类型更加丰富,包括数据流,更加适用于上传文件场景
public interface GetRequest_Interface {
/**
* {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
* 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
/**
* PartMap 注解支持一个Map作为参数,支持 {@link RequestBody } 类型,
* 如果有其它的类型,会被{@link retrofit2.Converter}转换,如后面会介绍的 使用{@link com.google.gson.Gson} 的 {@link retrofit2.converter.gson.GsonRequestBodyConverter}
* 所以{@link MultipartBody.Part} 就不适用了,所以文件只能用<b> @Part MultipartBody.Part </b>
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload2(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file);
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload3(@PartMap Map<String, RequestBody> args);
}
// 具体使用
MediaType textType = MediaType.parse("text/plain");
RequestBody name = RequestBody.create(textType, "Carson");
RequestBody age = RequestBody.create(textType, "24");
RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容");
// @Part
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);
ResponseBodyPrinter.printResponseBody(call3);
// @PartMap
// 实现和上面同样的效果
Map<String, RequestBody> fileUpload2Args = new HashMap<>();
fileUpload2Args.put("name", name);
fileUpload2Args.put("age", age);
//这里并不会被当成文件,因为没有文件名(包含在Content-Disposition请求头中),但上面的 filePart 有
//fileUpload2Args.put("file", file);
Call<ResponseBody> call4 = service.testFileUpload2(fileUpload2Args, filePart); //单独处理文件
ResponseBodyPrinter.printResponseBody(call4);
}
e. @Query和@QueryMap
- 作用:用于 @GET 方法的查询参数(Query = Url 中 ‘?’ 后面的 key-value)
如:url = http://www.println.net/?cate=android](http://www.println.net/?cate=android),其中,Query = cate
- 具体使用:配置时只需要在接口方法中增加一个参数即可:
@GET("/")
Call<String> cate(@Query("cate") String cate);
}
// 其使用方式同 @Field与@FieldMap,这里不作过多描述
f. @Path
- 作用:URL地址的缺省值
- 具体使用:
public interface GetRequest_Interface {
@GET("users/{user}/repos")
Call<ResponseBody> getBlog(@Path("user") String user );
// 访问的API是:https://api.github.com/users/{user}/repos
// 在发起请求时, {user} 会被替换为方法的第一个参数 user(被@Path注解作用)
}
g.@Url
- 作用:直接传入一个请求的URL变量用于URL设置
- 具体使用
public interface GetRequest_Interface {
@GET
Call<ResponseBody> testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll);
// 当有URL注解时,@GET传入的URL就可以省略
// 当GET、POST...HTTP等方法中没有设置Url时,则必须使用 {@link Url}提供
}
汇总
4.创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/") // 设置网络请求的Url地址
.addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 设置网络请求适配器
.build();
a.关于解析器(Converter)
- Retrofit支持多种数据解析方式
- 使用时需要在Gradle添加依赖
数据解析器 Gradle依赖
Gson com.squareup.retrofit2:converter-gson:2.0.2
Jackson com.squareup.retrofit2:converter-jackson:2.0.2
Simple XML com.squareup.retrofit2:converter-simplexml:2.0.2
Protobuf com.squareup.retrofit2:converter-protobuf:2.0.2
Moshi com.squareup.retrofit2:converter-moshi:2.0.2
Wire com.squareup.retrofit2:converter-wire:2.0.2
Scalars com.squareup.retrofit2:converter-scalars:2.0.2
b.关于网络请求适配器(CallAdapter)
- Retrofit支持多种网络请求适配器方式:guava java8 Rxjava
使用时如使用的是 Android 默认的 CallAdapter,则不需要添加网络请求适配器的依赖,否则则需要按照需求进行添加
Retrofit 提供的 CallAdapter
网络请求适配器 Gradle依赖
guava com.squareup.retrofit2:adapter-guava:2.0.2
Java8 com.squareup.retrofit2:adapter-java8:2.0.2
rxjava com.squareup.retrofit2:adapter-rxjava:2.0.2
5.创建网络请求接口实例
// 创建 网络请求接口 的实例
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
//对 发送请求 进行封装
Call<Reception> call = request.getCall();
6.发送网络请求(异步/同步)
//发送网络请求(异步)
call.enqueue(new Callback<Translation>() {
//请求成功时回调
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
//请求处理,输出结果
response.body().show();
}
//请求失败时候的回调
@Override
public void onFailure(Call<Translation> call, Throwable throwable) {
System.out.println("连接失败");
}
});
// 发送网络请求(同步)
Response<Reception> response = call.execute();
7.处理返回数据
通过response类的body()对返回数据进行处理
//发送网络请求(异步)
call.enqueue(new Callback<Translation>() {
//请求成功时回调
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
// 对返回数据进行处理
response.body().show();
}
//请求失败时候的回调
@Override
public void onFailure(Call<Translation> call, Throwable throwable) {
System.out.println("连接失败");
}
});
// 发送网络请求(同步)
Response<Reception> response = call.execute();
// 对返回数据进行处理
response.body().show();
实例
实例1:将中文翻译成英文
- 方案:采用Get方法对金山词霸API发送网络请求,使用Gson进行数据操作
步骤
1.添加Retrofit依赖
2.添加网络权限
3.创建接收服务器返回数据的类
// URL模板
http://fy.iciba.com/ajax.php
// URL实例
http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello%20world
// 参数说明:
// a:固定值 fy
// f:原文内容类型,日语取 ja,中文取 zh,英语取 en,韩语取 ko,德语取 de,西班牙语取 es,法语取 fr,自动则取 auto
// t:译文内容类型,日语取 ja,中文取 zh,英语取 en,韩语取 ko,德语取 de,西班牙语取 es,法语取 fr,自动则取 auto
// w:查询内容
- 根据服务器返回创建实例 Translation.java
public class Translation {
/**
* err_no : 0
* from : en-EU
* out : 示例
* to : zh-CN
* vendor : ciba
*/
private ContentEntity content;
/**
* content : {"err_no":0,"from":"en-EU","out":"示例","to":"zh-CN","vendor":"ciba"}
* status : 1
*/
private int status;
public ContentEntity getContent() {
return content;
}
public void setContent(ContentEntity content) {
this.content = content;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public static class ContentEntity {
private int err_no;
private String from;
private String out;
private String to;
private String vendor;
public int getErr_no() {
return err_no;
}
public void setErr_no(int err_no) {
this.err_no = err_no;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getOut() {
return out;
}
public void setOut(String out) {
this.out = out;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getVendor() {
return vendor;
}
public void setVendor(String vendor) {
this.vendor = vendor;
}
}
}
3.创建用于描述网络请求的接口
public interface RequestInterface {
// http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello%20world
@GET("ajax.php?a=fy&f=auto&t=auto&w=hello%20world")
Call<Translation> getCall();
}
- 后续步骤见代码
/**
* 网络请求方法
*/
private void getRequestData() {
//4.创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fy.iciba.com/")//设置url模版
.addConverterFactory(GsonConverterFactory.create())//设置数据解析器
.build();
//5.创建网络请求接口实例
RequestInterface requestInterface = retrofit.create(RequestInterface.class);
//封装请求
Call<Translation> translationCall = requestInterface.getCall();
//6.发送网络请求(异步)
translationCall.enqueue(new Callback<Translation>() {
//请求成功时回调
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
Log.d(TAG, "onResponse: " + response.body().toString());
}
//请求失败时回调
@Override
public void onFailure(Call<Translation> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.getMessage());
}
});
}
}
实例2
- 实现的功能 英文翻译中文
- 实现方法 post gson
创建接收服务器返回数据的类
- API数据格式说明
// URL
http://fanyi.youdao.com/translate
// URL实例
http://fanyi.youdao.com/translate?doctype=json&jsonversion=&type=&keyfrom=&model=&mid=&imei=&vendor=&screen=&ssid=&network=&abtest=
// 参数说明
// doctype:json 或 xml
// jsonversion:如果 doctype 值是 xml,则去除该值,若 doctype 值是 json,该值为空即可
// xmlVersion:如果 doctype 值是 json,则去除该值,若 doctype 值是 xml,该值为空即可
// type:语言自动检测时为 null,为 null 时可为空。英译中为 EN2ZH_CN,中译英为 ZH_CN2EN,日译中为 JA2ZH_CN,中译日为 ZH_CN2JA,韩译中为 KR2ZH_CN,中译韩为 ZH_CN2KR,中译法为 ZH_CN2FR,法译中为 FR2ZH_CN
// keyform:mdict. + 版本号 + .手机平台。可为空
// model:手机型号。可为空
// mid:平台版本。可为空
// imei:???。可为空
// vendor:应用下载平台。可为空
// screen:屏幕宽高。可为空
// ssid:用户名。可为空
// abtest:???。可为空
// 请求方式说明
// 请求方式:POST
// 请求体:i
// 请求格式:x-www-form-urlencoded
private String type;
private int errorCode;
private int elapsedTime;
private List<List<TranslateResultBean>> translateResult;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public int getElapsedTime() {
return elapsedTime;
}
public void setElapsedTime(int elapsedTime) {
this.elapsedTime = elapsedTime;
}
public List<List<TranslateResultBean>> getTranslateResult() {
return translateResult;
}
public void setTranslateResult(List<List<TranslateResultBean>> translateResult) {
this.translateResult = translateResult;
}
public static class TranslateResultBean {
/**
* src : merry me
* tgt : 我快乐
*/
public String src;
public String tgt;
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public String getTgt() {
return tgt;
}
public void setTgt(String tgt) {
this.tgt = tgt;
}
}
步骤全在以下代码中实现
private void getPostResquestData() {
//创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
PostRequestInterface postRequestInterface = retrofit.create(PostRequestInterface.class);
Call<YoudaoTranslation> translationCall = postRequestInterface.getCall("my name is wx");
translationCall.enqueue(new Callback<YoudaoTranslation>() {
@Override
public void onResponse(Call<YoudaoTranslation> call, Response<YoudaoTranslation> response) {
Log.d(TAG, "onResponse: " + response.body().toString());
}
@Override
public void onFailure(Call<YoudaoTranslation> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage());
}
});
}