參考:
- 網(wǎng)絡(luò)加載框架 - Retrofit
- 這是一份很詳細(xì)的 Retrofit 2.0 使用教程(含實例講解)
- Android:Retrofit 與 RxJava聯(lián)合使用大合集(含實例教程)!
使用流程
- 添加依賴
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
- 添加網(wǎng)絡(luò)權(quán)限
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
- 創(chuàng)建接收服務(wù)器返回數(shù)據(jù)的類
public class Persion {
...
// 根據(jù)返回數(shù)據(jù)的格式和數(shù)據(jù)解析方式(Json扫茅、XML等)定義
// 下面會在實例進(jìn)行說明
}
- 創(chuàng)建用于描述網(wǎng)絡(luò)請求的接口
public interface GetRequest_Interface {
@GET("persion")
Call<Persion> getPersion();
// @GET注解的作用:采用Get方法發(fā)送網(wǎng)絡(luò)請求
// getCall() = 接收網(wǎng)絡(luò)請求數(shù)據(jù)的方法
// 其中返回類型為Call<*>没陡,*是接收數(shù)據(jù)的類(即上面定義的Persion類)
// 如果想直接獲得Responsebody中的內(nèi)容,可以定義網(wǎng)絡(luò)請求返回值為Call<ResponseBody>
- 創(chuàng)建Retrofit對象
Retrofit retrofit=new Retrofit.Builder()
.baseUrl("address/") //設(shè)置網(wǎng)絡(luò)請求的URL地址
.addConverterFactory(GsonConverterFactory.create()) //設(shè)置數(shù)據(jù)解析器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava平臺
.build();
完整的URL地址=baseUrl+@GET()中的參數(shù)
上面的請求地址:address/persion
有一點注意如果是本機(jī)測試不要用localhost和127.0.0.1
還可以用動態(tài)傳遞請求參數(shù)
ConverterFactory和CallAdapterFactory請往后看
- 創(chuàng)建網(wǎng)絡(luò)請求接口實例 并 配置網(wǎng)絡(luò)請求參數(shù)
GetPersion_Interface getPersion_interface=retrofit.create(GetPersion_Interface.class);
Call<Persion> call=getPersion_interface.getPersion();
- 發(fā)送網(wǎng)絡(luò)請求(異步 / 同步)
call.enqueue(new Callback<Persion>() {
@Override
public void onResponse(Call<Persion> call, Response<Persion> response) {
textView.setText("Id:"+response.body().getId()+" "+"Name:"+response.body().getName()+" "+"Age:"+response.body().getAge());
}
@Override
public void onFailure(Call<Persion> call, Throwable t) {
textView.setText("請求失敗");
}
});
這里采用異步操作
在這里有一個注意點蔫敲,如果要返回ResponseBody的話,response.body().string()而不是toString
注解類型
網(wǎng)絡(luò)請求方法注解
注解 | 解釋 |
---|---|
@GET | 請求指定的頁面信息,并返回實體主體 |
@POST | 向指定資源提交數(shù)據(jù)進(jìn)行處理請求(例如提交表單或者上傳文件)队秩。數(shù)據(jù)被包含在請求體中。POST請求可能會導(dǎo)致新的資源的建立和/或已有資源的修改 |
@PUT | 從客戶端向服務(wù)器傳送的數(shù)據(jù)取代指定的文檔的內(nèi)容 |
@HEAD | 類似于get請求昼浦,只不過返回的響應(yīng)中沒有具體的內(nèi)容馍资,用于獲取報頭 |
@DELETE | 請求服務(wù)器刪除指定的頁面 |
@CONNECT | HTTP/1.1協(xié)議中預(yù)留給能夠?qū)⑦B接改為管道方式的代理服務(wù)器。 |
@OPTIONS | 允許客戶端查看服務(wù)器的性能关噪。 |
@HTTP | 用于替換以上7個注解的作用以及更多功能拓展 |
- @HTTP描述
如下:
public interface GetRequest_Interface {
/**
* method:網(wǎng)絡(luò)請求的方法(區(qū)分大小寫)
* path:網(wǎng)絡(luò)請求地址路徑
* hasBody:是否有請求體
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getCall(@Path("id") int id);
// {id} 表示是一個變量
// method 的值 retrofit 不會做處理鸟蟹,所以要自行保證準(zhǔn)確
}
標(biāo)記類注解
注解 | 解釋 |
---|---|
@FormUrlEncoded | 表示請求體是一個Form表單 |
@Multipart | 表示請求體是一個支持文件上傳的Form表單 |
@Streaming | 表示數(shù)據(jù)以流的形式返回,適用于返回數(shù)據(jù)大的情況(如果沒有該注解使兔,默認(rèn)把數(shù)據(jù)全部載入內(nèi)存建钥,之后獲取數(shù)據(jù)也是從內(nèi)存中提取) |
- @FormUrlEncoded
表示發(fā)送form-encoded的數(shù)據(jù)
每個鍵值對需要用@Filed來注解鍵名虐沥,隨后的對象需要提供值锦针。
- @Multipart
作用:表示發(fā)送form-encoded的數(shù)據(jù)(適用于 有文件 上傳的場景)
每個鍵值對需要用@Part來注解鍵名,隨后的對象需要提供值置蜀。
具體使用如下:
GetRequest_Interface
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} 中已經(jīng)包含了表單字段的信息),
*/
@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);
網(wǎng)絡(luò)請求參數(shù)注解
注解 | 解釋 |
---|---|
@Headers | 添加請求頭(注釋在方法上) |
@Header | 添加不固定值的請求頭(用在參數(shù)中) |
@Body | 用于非表單請求體( 不能用在get 請求方法) |
@Field | 向Post表單傳入鍵值對 |
@FieldMap | 向Post表單傳入鍵值對(多個) |
@Part | 用于表單字段秋秤,適用于有文件上傳的情況 |
@PartMap | 用于表單字段宏粤,適用于有文件上傳的情況 |
@Query | 用于表單字段用在get方法上 |
@QueryMap | 用于表單字段用在get方法上 |
@Path | URL缺省值 |
@URL | URL設(shè)置 |
@Field @Body一般用于Post方法,參數(shù)在請求體里
@Query 用在get方法灼卢,參數(shù)在請求頭
- @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作用于方法
- @Body
以 Post方式 傳遞 自定義數(shù)據(jù)類型 給服務(wù)器,類的實例啥的
特別注意:如果提交的是一個Map崇堰,那么作用相當(dāng)于 @Field
不過Map要經(jīng)過 FormBody.Builder 類處理成為符合 Okhttp 格式的表單,如:
FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");
- @Field & @FieldMap
發(fā)送 Post請求 時提交請求的表單字段
具體使用:與 @FormUrlEncoded 注解配合使用
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);
- @Part & @PartMap
發(fā)送 Post請求 時提交請求的表單字段
與@Field的區(qū)別:功能相同海诲,但攜帶的參數(shù)類型更加豐富,包括數(shù)據(jù)流檩互,所以適用于 有文件上傳 的場景 與 @Multipart 注解配合使用
public interface GetRequest_Interface {
/**
* {@link Part} 后面支持三種類型特幔,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 闸昨、任意類型
* 除 {@link okhttp3.MultipartBody.Part} 以外蚯斯,其它類型都必須帶上表單字段({@link okhttp3.MultipartBody.Part} 中已經(jīng)包含了表單字段的信息)薄风,
*/
@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}轉(zhuǎn)換,如后面會介紹的 使用{@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"), "這里是模擬文件的內(nèi)容");
// @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);
//這里并不會被當(dāng)成文件撰茎,因為沒有文件名(包含在Content-Disposition請求頭中)嵌牺,但上面的 filePart 有
//fileUpload2Args.put("file", file);
Call<ResponseBody> call4 = service.testFileUpload2(fileUpload2Args, filePart); //單獨處理文件
ResponseBodyPrinter.printResponseBody(call4);
}
- @Query和@QueryMap
用于 @GET 方法的查詢參數(shù)(Query = Url 中 ‘?’ 后面的 key-value)
如:url = http://www.println.net/?cate=android,其中龄糊,Query = cate
具體使用:配置時只需要在接口方法中增加一個參數(shù)即可:
@GET("/")
Call<String> cate(@Query("cate") String cate);
}
// 其使用方式同 @Field與@FieldMap逆粹,這里不作過多描述
- @Path
URL地址的缺省值,用@Path注解標(biāo)志要傳到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注解作用)
}
- @Url
直接傳入一個請求的 URL變量 用于URL設(shè)置
public interface GetRequest_Interface {
@GET
Call<ResponseBody> testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll);
// 當(dāng)有URL注解時炫惩,@GET傳入的URL就可以省略
// 當(dāng)GET僻弹、POST...HTTP等方法中沒有設(shè)置Url時,則必須使用 {@linlk Url}提供
}
數(shù)據(jù)解析器(Converter)
Retrofit支持多種數(shù)據(jù)解析方式
使用時需要在Gradle添加依賴
數(shù)據(jù)解析器 | Gradle依賴 |
---|---|
Gson | implementation 'com.squareup.retrofit2:converter-gson:2.4.0' |
Jackson | implementation 'com.squareup.retrofit2:converter-jackson:2.4.0' |
Simple XML | implementation 'com.squareup.retrofit2:converter-simplexml:2.0.2' |
Protobuf | implementation 'com.squareup.retrofit2:converter-protobuf:2.4.0' |
Moshi | implementation 'com.squareup.retrofit2:converter-moshi:2.4.0' |
Wire | implementation 'com.squareup.retrofit2:converter-wire:2.4.0' |
Scalars | implementation 'com.squareup.retrofit2:converter-scalars:2.4.0' |
網(wǎng)絡(luò)請求適配器(CallAdapter)
- Retrofit支持多種網(wǎng)絡(luò)請求適配器方式:guava他嚷、Java8和rxjava
使用時如使用的是 Android 默認(rèn)的 CallAdapter蹋绽,則不需要添加網(wǎng)絡(luò)請求適配器的依賴,否則則需要按照需求進(jìn)行添加 Retrofit 提供的 CallAdapter
- 使用時需要在Gradle添加依賴:
網(wǎng)絡(luò)請求適配器 | Gradle依賴 |
---|---|
rxjava | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' |
Java8 | implementation 'com.squareup.retrofit2:adapter-java8:2.4.0' |
guava | implementation 'com.squareup.retrofit2:adapter-guava:2.4.0' |
發(fā)送網(wǎng)絡(luò)請求
封裝了 數(shù)據(jù)轉(zhuǎn)換筋蓖、線程切換的操作
//發(fā)送網(wǎng)絡(luò)請求(異步)
call.enqueue(new Callback<Translation>() {
//請求成功時回調(diào)
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
//請求處理,輸出結(jié)果
response.body().show();
}
//請求失敗時候的回調(diào)
@Override
public void onFailure(Call<Translation> call, Throwable throwable) {
System.out.println("連接失敗");
}
});
// 發(fā)送網(wǎng)絡(luò)請求(同步)
Response<Reception> response = call.execute();