原帖地址: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開發(fā)的Volley功能上非常相似拆座,但是Retrofit使用起來更加方便芭梯,Retrofit的設計也更加合理
Retrofit有什么優(yōu)點
- Retrofit依賴于okHttp,需要集成okHttp
- Retrofit通過注解配置網絡請求參數(shù)
- 支持同步/異步的請求
- 提供對RxJava支持
Retrofit是一個Restful的HTTP網絡請求框架的封裝暖璧,因為網絡請求的工作本質上是OkHttp完成,而Retrofit僅僅是負責對網絡請求接口的封裝琳袄,App應用程序通過Retrofit請求網絡摧扇,實際上是使用Retrofit接口層封裝請求參數(shù)、Header挚歧、URL等信息扛稽,之后由OkHttp完成后續(xù)的請求操作。
在服務端返回數(shù)據(jù)后滑负,OkHttp將原始的結果交給Retrofit在张,Retrofit根據(jù)用戶的需求對結果進行解析
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.創(chuàng)建接收服務器返回數(shù)據(jù)的類
3.創(chuàng)建用于描述網絡請求的接口
- Retrofit將Http請求抽象成Java接口:采用注解描述網絡請求參數(shù)和配置網絡請求參數(shù)
- 用動態(tài)代理動態(tài)將該接口的"注解"翻譯成一個Http請求,最后再執(zhí)行Http請求
- 接口中的每個方法的參數(shù)都需要使用注解標注
注解類型
第一類 網絡請求方法
- @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方法發(fā)送網絡請求
// getCall() = 接收網絡請求數(shù)據(jù)的方法
// 其中返回類型為Call<*>矮慕,*是接收數(shù)據(jù)的類(即上面定義的Translation類)
}
- Retrofit把網絡請求的URL分成了兩部分設置
//第1部分 在網絡請求接口的注解設置
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation> getCall()
//第2部分 在創(chuàng)建Retrofit實例時通過.baseUrl()設置
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/") //設置網絡請求的Url地址
.addConverterFactory(GsonConverterFactory.create()) //設置數(shù)據(jù)解析器
.build();
- 一個請求的URL可以通過替換塊和請求方法的參數(shù)來進行動態(tài)的URL更新帮匾,替換塊是由被{}包裹起來的字符串構成
Retrofit網絡請求的完整URL具體整合規(guī)則
- @HTTP
- 作用:替換@GET、@POST痴鳄、@PUT瘟斜、@DELETE、@HEAD注解的作用 及 更多功能拓展
- 具體使用:通過屬性method痪寻、path螺句、hasBody進行設置
public interface GetRequest_Interface {
/**
* method:網絡請求的方法(區(qū)分大小寫)
* path:網絡請求地址路徑
* hasBody:是否有請求體
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getCall(@Path("id") int id);
// {id} 表示是一個變量
// method 的值 retrofit 不會做處理,所以要自行保證準確
}
第二類標記
a. @FormUrlEncoded
- 作用:表示發(fā)送form-encoded的數(shù)據(jù)
每個鍵值對需要用@Filed來注解鍵名橡类,隨后的對象需要提供值
b. @Multipart
- 作用:表示發(fā)送form-encoded的數(shù)據(jù)(適用于文件上傳的場景)
每個鍵值對要用@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);
第三類 網絡請求參數(shù)
a. @Header & @ Headers
- 作用:添加請求頭&添加不固定的請求頭
// @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()
// 以上的效果是一致的谱邪。
// 區(qū)別在于使用場景和使用方式
// 1. 使用場景:@Header用于添加不固定的請求頭炮捧,@Headers用于添加固定的請求頭
// 2. 使用方式:@Header作用于方法的參數(shù);@Headers作用于方法
b.@Body
- 作用:以Post方式傳遞自定義數(shù)據(jù)類型給服務器
- 注意:如果提交的是一個Map惦银,作用相當于@Field
c.@Field&@FieldMap
*作用:發(fā)送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
// 實現(xiàn)的效果與上面相同,但要傳入Map
Map<String, Object> map = new HashMap<>();
map.put("username", "Carson");
map.put("age", 24);
Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
d @Part&@PartMap
- 作用:發(fā)送Post請求時提交請求的表單字段
與Field功能相同璧函,但攜帶的參數(shù)類型更加豐富,包括數(shù)據(jù)流基显,更加適用于上傳文件場景
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作為參數(shù)窜醉,支持 {@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
// 實現(xiàn)和上面同樣的效果
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 方法的查詢參數(shù)(Query = Url 中 ‘?’ 后面的 key-value)
如:url = http://www.println.net/?cate=android](http://www.println.net/?cate=android)琅催,其中居凶,Query = cate
- 具體使用:配置時只需要在接口方法中增加一個參數(shù)即可:
@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
// 在發(fā)起請求時藤抡, {user} 會被替換為方法的第一個參數(shù) 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.創(chuàng)建Retrofit實例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/") // 設置網絡請求的Url地址
.addConverterFactory(GsonConverterFactory.create()) // 設置數(shù)據(jù)解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 設置網絡請求適配器
.build();
a.關于解析器(Converter)
- Retrofit支持多種數(shù)據(jù)解析方式
- 使用時需要在Gradle添加依賴
數(shù)據(jù)解析器 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.創(chuàng)建網絡請求接口實例
// 創(chuàng)建 網絡請求接口 的實例
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
//對 發(fā)送請求 進行封裝
Call<Reception> call = request.getCall();
6.發(fā)送網絡請求(異步/同步)
//發(fā)送網絡請求(異步)
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("連接失敗");
}
});
// 發(fā)送網絡請求(同步)
Response<Reception> response = call.execute();
7.處理返回數(shù)據(jù)
通過response類的body()對返回數(shù)據(jù)進行處理
//發(fā)送網絡請求(異步)
call.enqueue(new Callback<Translation>() {
//請求成功時回調
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
// 對返回數(shù)據(jù)進行處理
response.body().show();
}
//請求失敗時候的回調
@Override
public void onFailure(Call<Translation> call, Throwable throwable) {
System.out.println("連接失敗");
}
});
// 發(fā)送網絡請求(同步)
Response<Reception> response = call.execute();
// 對返回數(shù)據(jù)進行處理
response.body().show();
實例
實例1:將中文翻譯成英文
- 方案:采用Get方法對金山詞霸API發(fā)送網絡請求瓷式,使用Gson進行數(shù)據(jù)操作
步驟
1.添加Retrofit依賴
2.添加網絡權限
3.創(chuàng)建接收服務器返回數(shù)據(jù)的類
// URL模板
http://fy.iciba.com/ajax.php
// URL實例
http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello%20world
// 參數(shù)說明:
// a:固定值 fy
// f:原文內容類型替饿,日語取 ja,中文取 zh贸典,英語取 en盛垦,韓語取 ko,德語取 de瓤漏,西班牙語取 es腾夯,法語取 fr颊埃,自動則取 auto
// t:譯文內容類型,日語取 ja蝶俱,中文取 zh班利,英語取 en,韓語取 ko榨呆,德語取 de罗标,西班牙語取 es,法語取 fr积蜻,自動則取 auto
// w:查詢內容
- 根據(jù)服務器返回創(chuàng)建實例 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.創(chuàng)建用于描述網絡請求的接口
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();
}
- 后續(xù)步驟見代碼
/**
* 網絡請求方法
*/
private void getRequestData() {
//4.創(chuàng)建Retrofit對象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fy.iciba.com/")//設置url模版
.addConverterFactory(GsonConverterFactory.create())//設置數(shù)據(jù)解析器
.build();
//5.創(chuàng)建網絡請求接口實例
RequestInterface requestInterface = retrofit.create(RequestInterface.class);
//封裝請求
Call<Translation> translationCall = requestInterface.getCall();
//6.發(fā)送網絡請求(異步)
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
- 實現(xiàn)的功能 英文翻譯中文
- 實現(xiàn)方法 post gson
創(chuàng)建接收服務器返回數(shù)據(jù)的類
- API數(shù)據(jù)格式說明
// 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=
// 參數(shù)說明
// 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:手機型號酪惭∠3眨可為空
// 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;
}
}
步驟全在以下代碼中實現(xiàn)
private void getPostResquestData() {
//創(chuàng)建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());
}
});
}