1.Retrofit簡介
A type-safe HTTP client for Android and Java,封裝了OkHttp,也是由Square公司貢獻的一個處理網路請求的
開源專案,
github地址:https://github.com/square/retrofit
引入依賴(具體訪問github獲取最新的依賴):
implementation ‘com.squareup.retrofit2:retrofit:2.9.0’
引入Retrofit后就不用了引入OkHttp,因為Retrofit封裝了OkHttp
2.Retrofit基本使用一

一、根據Http介面創建Java介面(導包的時候一定不要導錯,要導的是Retrofit的Call):
public interface HttpbinService {
@POST
@FormUrlEncoded
Call<Response>post(@Field("username")String name,@Field("password")String pwd);
@GET
Call<Response>get(@Query("username")String name,@Query("password")String pwd);
}
3.Retrofit基本使用二
二、創建Retrofit物件,并生成介面實作類物件:
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://www.httpbin.org/").build();
HttpbinService httpbinService = retrofit.create(HttpbinService.class);
三、介面實作類物件呼叫對應方法獲得回應:
retrofit2.Call<ResponseBody> call = httpbinService.post("lance", "123");
call.enqueue(new retrofit2.Callback<ResponseBody>() {
@Override
public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
try {
Log.i(TAG, "postAsync: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(retrofit2.Call<ResponseBody> call, Throwable t) {
}
});
4.Retrofit的注解
方法注解:@GET,@POST,@PUT,@DELETE,@PATH,@HEAD,@OPTIONS,@HTTP ?
標記注解:@FormUrlEncoded,@Multipart,@Streaming ?
引數注解:@Query,@QueryMap,@Body,@Field,@FieldMap,@Part,@PartMap ?
其他注解:@Path,@Header, @Headers,@Url
4.1@HTTP:
- 作用于方法,用于發送一個自定義的HTTP請求
示例:
//介面
@HTTP(method = "POST", path = "get", hasBody = true)
Call<ResponseBody> http(@Query("username") String userName, @Query("password") String pwd);
4.2@Body:
- 作用于方法的引數
- 使用該注解定義的引數不可為null
- 當你發送一個post或put請求,但是又不想作為請求引數或表單的方式發送請求時,使用該注解定義的引數可以直接傳入一個物體類,retrofit會通過convert把該物體序列化并將序列化后的結果直接作為請求體發送出去.
示例:
//介面
@POST("post")
Call<ResponseBody> postBody(@Body RequestBody body);
//實體
@Test
public void bodyTest() throws IOException {
FormBody formBody = new FormBody.Builder()
.add("a", "1").add("b", "2").build();
Response<ResponseBody> response = httpbinService.postBody(formBody).execute();
System.out.println(response.body().string());
}
4.3 @Path:
- 作用于方法的引數,用于定義Multipart請求的每個part
- 使用該注解定義的引數,引數值可以為空,為空時,則忽略
- 使用該注解定義的引數型別有以下3種方式可選:
如果型別是okhttp3.MultipartBody.Part,內容將被直接使用,省略part中的名稱,即 @Part MultipartBody.Part part
如果型別是RequestBody,那么該值將直接與其內容型別一起使用,
在注釋中提供part名稱(例如,@Part(“foo”)RequestBody foo),
其他物件型別將通過使用轉換器轉換為適當的格式, 在注釋中提供part名稱(例如,@Part(“foo”)Image photo),
示例:
//介面
@POST("{id}")
@FormUrlEncoded
Call<ResponseBody> postInPath(@Path("id") String path, @Header("os") String os, @Field("username") String userName, @Field("password") String pwd);
//實體
@Test
public void pathTest() throws IOException {
// https://www.httpbin.org/post
Response<ResponseBody> response = httpbinService.postInPath("post", "android", "lance", "123").execute();
System.out.println(response.body().string());
}
4.4@Header
- 作用于方法的引數,用于添加請求頭
- 使用該注解定義的請求頭可以為空,當為空時,會自動忽略,當傳入一個List或array時,為拼接每個非空的item的值到請求頭中.
- 具有相同名稱的請求頭不會相互覆寫,而是會照樣添加到請求頭中
4.5@Headers
- 作用于方法,用于添加一個或多個請求頭
- 具有相同名稱的請求頭不會相互覆寫,而是會照樣添加到請求頭中
示例:
//介面
@Headers({"os:android", "version:1.0"})
@POST("post")
Call<ResponseBody> postWithHeaders();
//實體
@Test
public void headersTest() throws IOException {
Call<ResponseBody> response = httpbinService.postWithHeaders();
System.out.println(response.execute().body().string());
}
4.6@Url
- 作用于方法引數
- 用于添加請求的介面地址
示例:
//介面
@POST
Call<ResponseBody> postUrl(@Url String url);
//實體
@Test
public void urlTest() throws IOException {
Response<ResponseBody> response = httpbinService.postUrl("https://www.httpbin.org/post").execute();
System.out.println(response.body().string());
}
更多Retrofit注解知識可參考:鏈接
5.Retrofit的轉換器
在我們接到服務器的回應后,目前無論是OkHttp還是Retrofit都只能接收到String字串型別的資料,在實際開發中, 我們經常需要對字串進行決議將其轉變為一個Java Bean物件,比如服務器回應資料為JSON格式字串,那么我 們可以自己利用GSON庫完成反序列化的操作,而Retrofit提供了多個轉換器使得回應能夠完成自動的資料轉換,以 json決議為例:
添加依賴: implementation ‘com.squareup.retrofit2:converter-gson:2.9.0’
修改介面方法:
@POST("post") @FormUrlEncoded Call<JavaBean> post(@Field("username") String userName, @Field("password") String pwd);
這里測驗依舊是采用玩安卓的開放API:https://www.wanandroid.com/blog/show/2

這里使用到Talend API Tester ,安裝和使用具體參考:
https://blog.csdn.net/yuanfate/article/details/108615333
https://www.cccitu.com/3391.html
我們使用Talend API Tester插件訪問玩安卓的API介面(這里POST的是我們已經注冊好的賬號),回傳的資料是json格式的:
{"data":{"admin":false,"chapterTops":[],"coinCount":2568,"collectIds":[17188,18965,20087,19623],"email":"","icon":"","id":86459,"nickname":"lanceedu","password":"","publicName":"lanceedu","token":"","type":0,"username":"lanceedu"},"errorCode":0,"errorMsg":""}

這里又用到了https://www.bejson.com/jsonviewernew/來幫助我們進行json的格式的轉換:

由此我們就可以按照這個格式自己創建物體類,當然自己寫java物體類還過于繁瑣,我們這個可以用到bejson網站通過json轉換為Java物體類(在轉換之前自己先寫好包名類名),生成好后點擊下載再將代碼直接匯入專案中即可:


代碼示例:
1.手動反序列化
public interface WanAndroidService {
//介面
@POST("user/login")
@FormUrlEncoded
Call<ResponseBody> login(@Field("username") String username, @Field("password") String pwd);
}
@Test public void loginTest() throws IOException {
Call<ResponseBody> call =
wanAndroidService.login("lanceedu", "123123");
Response<ResponseBody> response = call.execute();
String result = response.body().string();
System.out.println(result);
//手動進行資料轉換
BaseResponse baseResponse = new Gson().fromJson(result, BaseResponse.class);
System.out.println(baseResponse);
運行測驗代碼后我們就能得到反序列化后的格式:

2.利用轉換器反序列化
ResponseBody改為BaseResponse(物體類)
public interface WanAndroidService2 {
//介面
@POST("user/login")
@FormUrlEncoded
Call<BaseResponse> login(@Field("username") String username, @Field("password") String pwd);
}
@Test
public void loginConvertTest() throws IOException {
Call<BaseResponse> call = wanAndroidService2.login("lanceedu", "123123");
Response<BaseResponse> response = call.execute();
BaseResponse baseResponse = response.body();
System.out.println(baseResponse);
}
Retrofit實體化時一定要添加轉換器!
.addConverterFactory(GsonConverterFactory.create()) //添加轉換器
運行代碼后得到反序列后的資料:

6.Retrofit的嵌套請求和配接器
在實際開發中,可能會存在:需要先請求A介面,再請求B介面的情況,比如需要請求獲取收藏文章串列,但是需 要先登錄拿到Cookie才能請求收藏文章串列介面,此時請求就有了先后順序,為了完成這個功能,我們需要這樣實 現代碼:

Retrofit的介面方法回傳型別必須是Call,如果能夠將Call改為RxJava中的Observable,對于嵌套的情況,就能得到非 常方便優雅的解決,這就是配接器的功能,如果我們想要回傳的不是Call,配接器就能夠幫助我們轉換為其他型別, 以RxJava3為例:
添加依賴: implementation ‘com.squareup.retrofit2:adapter-rxjava3:2.9.0’
修改介面方法:
@POST("post") @FormUrlEncoded Observable<JavaBean> post(@Field("username") String userName, @Field("password") String pwd);
這里我們測驗還是用到玩安卓的開放API:

代碼示例(用到了cookie的知識,具體參考我之前的文章https://blog.csdn.net/Lbsssss/article/details/121057667):
public interface WanAndroidService2 {
//介面
@POST("user/login")
@FormUrlEncoded
Flowable<BaseResponse> login2(@Field("username") String username, @Field("password") String pwd);
@GET("lg/collect/list/{pageNum}/json")
Flowable<ResponseBody> getArticle(@Path("pageNum") int pageNum);
}
//具體實作
Map<String, List<Cookie>> cookies = new HashMap<>();
Retrofit retrofit3 = new Retrofit.Builder()
.baseUrl("https://www.wanandroid.com/")
.callFactory(new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {
cookies.put(httpUrl.host(), list);
}
@NotNull
@Override
public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
List<Cookie> cookies = WanAndroidUnitTest.this.cookies.get(httpUrl.host());
return cookies == null ? new ArrayList<>() : cookies;
}
}).build())
.addConverterFactory(GsonConverterFactory.create()) //添加轉換器
.addCallAdapterFactory(RxJava3CallAdapterFactory.create()) // 添加配接器
.build();
WanAndroidService2 wanAndroidService3 = retrofit3.create(WanAndroidService2.class);
@Test
public void rxjavaTest() {
wanAndroidService3.login2("lanceedu", "123123")
.flatMap(new Function<BaseResponse, Publisher<ResponseBody>>() {
@Override
public Publisher<ResponseBody> apply(BaseResponse baseResponse) throws Throwable {
return wanAndroidService3.getArticle(0);
}
})
.observeOn(Schedulers.io())
.subscribeOn(Schedulers.newThread())
.subscribe(new Consumer<ResponseBody>() {
@Override
public void accept(ResponseBody responseBody) throws Throwable {
System.out.println(responseBody.string());
}
});
while (true) {
}
}
最后能得到收藏的文章串列:

7.檔案上傳與下載:
1.上傳檔案(與OkHttp類似):
//介面
@POST("post")
@Multipart
Call<ResponseBody> upload(@Part MultipartBody.Part file);
@Test
public void uploadFileTest() throws IOException {
File file1 = new File("C:\\Users\\Administrator\\Desktop\\1.txt");
MultipartBody.Part part = MultipartBody.Part.createFormData("file1",
"1.txt", RequestBody.create(file1, MediaType.parse("text/plain")));
Call<ResponseBody> call =
uploadService.upload(part);
System.out.println(call.execute().body().string());
}
2.下載檔案(兩種):
//介面 兩種方式
@Streaming
@GET
Call<ResponseBody> download(@Url String url);
@Streaming
@GET
Flowable<ResponseBody> downloadRxJava(@Url String url);
@Test
public void downloadTest() throws IOException {
Response<ResponseBody> response = uploadService.download(
"https://fga1.market.xiaomi.com/download/AppStore/07adf043b0b2c40371abc6c685363e83d27f3efd7/com.sdu.didi.psnger.apk")
.execute();
// response.isSuccessful()
InputStream inputStream = response.body().byteStream();
FileOutputStream fos = new FileOutputStream("C:\\Users\\劉博\\Desktop\\a.apk");
int len;
byte[] buffer = new byte[4096];
while ((len = inputStream.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.close();
inputStream.close();
}
@Test
public void downloadRxjavaTest() {
uploadService.downloadRxJava("https://fga1.market.xiaomi.com/download/AppStore/07adf043b0b2c40371abc6c685363e83d27f3efd7/com.sdu.didi.psnger.apk")
.map(new Function<ResponseBody, File>() {
@Override
public File apply(ResponseBody responseBody) throws Throwable {
InputStream inputStream = responseBody.byteStream();
File file = new File("C:\\Users\\劉博\\Desktop\\a.apk");
FileOutputStream fos = new FileOutputStream(file);
int len;
byte[] buffer = new byte[4096];
while ((len = inputStream.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.close();
inputStream.close();
return file;
}
}).subscribe(new Consumer<File>() {
@Override
public void accept(File file) throws Throwable {
}
});
while (true) {
}
}
運行代碼就能在指定路徑得到下載的apk了:

本文demo:https://github.com/gujunhe/NetworkDemo.git
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/343165.html
標籤:其他
上一篇:解決Vue專案在iOS 10 報錯 “Cannot declare a let variable twice: ‘r‘”
