知識(shí)框架(腦圖)
出現(xiàn)背景
移動(dòng)端網(wǎng)絡(luò)請(qǐng)求復(fù)雜缺猛,代碼冗余
解決思路
Retrofit:給Android和Java用的類型安全的HTTP客戶端剔桨,將網(wǎng)絡(luò)請(qǐng)求抽象成接口睦柴,以注解形式定義HTTP請(qǐng)求,Retrofit會(huì)自動(dòng)生成對(duì)應(yīng)的實(shí)現(xiàn)供開發(fā)人員調(diào)用捕犬。
具體步驟
(1)添加網(wǎng)絡(luò)訪問權(quán)限并引入依賴庫
<uses-permission android:name="android.permission.INTERNET"/>
compile 'com.squareup.retrofit2:retrofit:2.1.0'
(2)使用注解定義網(wǎng)絡(luò)訪問的API
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
有哪些注解呢?
- URL參數(shù)和Query參數(shù)
- 對(duì)象到請(qǐng)求體的轉(zhuǎn)換(eg : JSON,protocol buffers)
- 表單提交和文件上傳
(3)使用Retrofit生成該接口的一個(gè)實(shí)現(xiàn)
使用Builder構(gòu)建一個(gè)Retrofit酵镜,并調(diào)用Retrofit的create方法創(chuàng)建一個(gè)接口實(shí)現(xiàn)碉碉。構(gòu)建的時(shí)候需要提供baseUrl,而接口定義時(shí)使用相對(duì)路徑即可淮韭。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create()) //這里使用Gson轉(zhuǎn)換器垢粮,需要添加相應(yīng)依賴,見問題1
.build();
GitHubService service = retrofit.create(GitHubService.class);
(4)調(diào)用實(shí)現(xiàn)的方法來進(jìn)行同步或異步的HTTP請(qǐng)求
Call<List<Repo>> repos = service.listRepos("octocat");
// 同步請(qǐng)求
List<Repo> repoList = repos.execute().body();
// 異步請(qǐng)求
repos.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// response.body().string();
}
});
調(diào)用接口方法之后返回的是Call對(duì)象靠粪,可以被異步或同步執(zhí)行蜡吧,每個(gè)實(shí)例只能使用一次,當(dāng)然可以使用clone()造一個(gè)新的來用占键。還可以通過cancle方法取消Call~
在Android昔善,回調(diào)會(huì)在主線程執(zhí)行;而在JVM畔乙,回調(diào)會(huì)在發(fā)起HTTP請(qǐng)求的線程執(zhí)行君仆;這是自動(dòng)完成的!牲距!
(5)進(jìn)階:操作URL
使用替換塊和方法中的參數(shù)動(dòng)態(tài)地更新請(qǐng)求的URL返咱。替換塊的組成:用花括號(hào)包裹起來的僅含字母數(shù)字的字符串;而參數(shù)需要使用@Path注解和相同的字符串牍鞠。例如:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
也可以使用@Query注解添加查詢參數(shù)咖摹,如:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
復(fù)雜點(diǎn)的查詢參數(shù)可以結(jié)合成一個(gè)Map再用,如:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
(6)進(jìn)階:請(qǐng)求體
對(duì)象可以作為HTTP的請(qǐng)求體(使用@Body注解)难述,也可以使用轉(zhuǎn)換器轉(zhuǎn)成特定的字符串楞艾,比如JSON参咙。
@POST("users/new")
Call<User> createUser(@Body User user);
(7)進(jìn)階:表單提交和文件上傳
使用@FormUrlEncoded標(biāo)明是表單上傳的方法,然后每一個(gè)鍵值對(duì)使用@Field關(guān)聯(lián):
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
使用@Multipart標(biāo)明是文件上傳的方法硫眯,然后使用@Part分隔各個(gè)部分:
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
(8)進(jìn)階:操作請(qǐng)求頭
使用@Headers設(shè)置靜態(tài)請(qǐng)求頭
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
注意:請(qǐng)求頭不會(huì)相互覆蓋蕴侧,同名的請(qǐng)求頭會(huì)被保留進(jìn)請(qǐng)求。
可以使用@Header動(dòng)態(tài)修改請(qǐng)求頭两入,如果值是null净宵,那么該頭部會(huì)被清除;還有toString方法會(huì)被調(diào)用裹纳。
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
(9)進(jìn)階:Retrofit配置轉(zhuǎn)換器
為什么要配置轉(zhuǎn)換器择葡?
Retrofit已經(jīng)不提供給默認(rèn)的轉(zhuǎn)換器了,需要相應(yīng)的轉(zhuǎn)換器剃氧,比如要用Gson解析的話就需要添加依賴并使用addConverterFactory方法在構(gòu)建Retrofit時(shí)配置好敏储。
有哪些轉(zhuǎn)換器可以用?
- Gson: com.squareup.retrofit2:converter-gson
- Jackson: com.squareup.retrofit2:converter-jackson
- Moshi: com.squareup.retrofit2:converter-moshi
- Protobuf: com.squareup.retrofit2:converter-protobuf
- Wire: com.squareup.retrofit2:converter-wire
- Simple XML: com.squareup.retrofit2:converter-simplexml
- Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
怎么添加轉(zhuǎn)換器朋鞍?
使用addConverterFactory
方法
// 以添加GsonConverterFactory為例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Q&A
問題1:IllegalArgumentException: Unable to create converter for class...
Retrofit已經(jīng)不提供給默認(rèn)的轉(zhuǎn)換器了已添,需要相應(yīng)的轉(zhuǎn)換器比如要用Gson解析的話就需要添加依賴:
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
然后構(gòu)建Retrofit時(shí)使用該轉(zhuǎn)換器:
Retrofit client = new Retrofit.Builder()
.baseUrl("https://github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
值得注意的是:JSON Converter要放置在最后,因?yàn)闆]有確切的條件可以判定一個(gè)對(duì)象是否是JSON對(duì)象滥酥。