因為之前Android開發第三方庫總結的文章在交流群分享廣受好評,就有不少朋友讓我推薦對應的功能庫。想著,既然大家都覺得不錯,那也想著順手把自己常用的這些功能庫給整理出來,今後要是問我怎麼用,直接甩文章。哈哈哈,想想都開心。
本文面向對象:有一定基礎的Android開發者。
本篇文章大致內容從如下三個方面講進行講解:
什麼是Retrofit?為什麼要用Retrofit?如何使用Retrofit?
Retrofit的常用註解以及使用場景。
如何給Retrofit設置攔截器。
當然,假若各位覺得內容寫得不好,本人不接受任何相關建議,批評。還是那句話:you can you up,no can no ……
好了,話不多說,今天講Retrofit。小板凳拿好,開始上課。坐後面的朋友請到前面來。
什麼是Retrofit?Retrofit,英文翻譯過來是翻新,改進的意思,光看名字很難聯想到他的具體作用,官方給的解釋是:Type-safe HTTP client for Android and Java by Square,翻譯過來就是由Square公司開發的一款針對Android網絡請求的框架,底層是基於OkHttp的。retrofit github地址
為什麼要用Retrofit? Retrofit有什麼優勢?在Android開發過程中,有很多的網絡請求框架,比如Volley、Async Http Client,我們為什麼要用Retrofit?
為什麼要用?一個詞描述:方便。使用方便,修改也方便。
Retrofit的優點:
缺點:
如何使用Retrofit?導包和權限申請當前文章編寫時最新版本為2.6.1。導包時到github去導入最新版本即可。
1implementation 'com.squareup.retrofit2:retrofit:2.6.1'
Retrofit有一系列的輔助包,當我們在導包的時候需要根據我們的數據返回導入對應的包,否則會報異常:
Could not locate ResponseBody converter for ……
比如我們需要通過Gson轉對象,我們需要增加如下Gson轉換輔助包:
1implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
如果我們使用了protobuf格式,那我們需要添加protobuf轉換輔助包:
1implementation 'com.squareup.retrofit2:converter-protobuf:2.6.2'
當然,還有很多輔助包:比如guava,jackson,jaxb,moshi,scalars等一系列輔助包,當然,這些在retrofit的retrofit-converters包下都有,有興趣的可以去深入了解。這裡也列出來供大家導入。
1Gson: compile 'com.squareup.retrofit2:converter-gson:2.6.2'
2Jackson: compile 'com.squareup.retrofit2:converter-jackson:2.6.2'
3Moshi: compile 'com.squareup.retrofit2:converter-moshi:2.6.2'
4Protobuf: compile 'com.squareup.retrofit2:converter-protobuf:2.6.2'
5Wire: compile 'com.squareup.retrofit2:converter-wire:2.6.2'
6Simple XML: compile 'com.squareup.retrofit2:converter-simplexml:2.6.2'
7Scalars (primitives, boxed, and String): compile 'com.squareup.retrofit2:converter-scalars:2.6.2'
導完包之後,咱們記得在AndroidManifest.xml中聲明網絡請求權限,添加如下代碼即可申請網絡請求權限。
1<uses-permission android:name="android.permission.INTERNET" />
好了,準備工作做完了,開始講使用步驟吧。
Retrofit的使用步驟這裡我們直接用官方給的例子來做示範:
1public interface IGitHubService {
2 @GET("users/{user}/repos")
3 Call<List<Repo>> listRepos(@Path("user") String user);
4}
1public class Repo {
2 ……
3 private String name;
4 public String getName() {
5 return name;
6 }
7}
1Retrofit retrofit = new Retrofit.Builder()
2 .baseUrl("https://api.github.com/")
3 .addConverterFactory(GsonConverterFactory.create())
4 .build();
5
6IGitHubService service = retrofit.create(IGitHubService.class);
7
8Call<List<Repo>> listRepos = service.listRepos("aserbao");
1listRepos.enqueue(new Callback<List<Repo>>() {
2 @Override
3 public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
4 updateUi(response.body());
5 }
6
7 @Override
8 public void onFailure(Call<List<Repo>> call, Throwable t) {
9
10 }
11 });
當然,有一些特殊情況,這裡也提一下:
當創建裝換對象中的字符不能使用時,我們可以使用annotations註解來解決這個問題。舉一個例子:json返回欄位中若返回private屬性,眾所周知private不能在Android中當屬性名,那這時候怎麼辦呢?可以這樣做:
1@com.google.gson.annotations.SerializedName("private")
2private boolean privateX;
好了,接下來介紹下Api的使用吧,Api的使用官方介紹也挺詳細的,這裡就作下簡單介紹。
Retrofit 註解上面使用案例中我們用了兩個註解,分別是@GET和@Path,他們的作用是什麼呢?是否有其他註解,接下來咱們一起去了解下Retrofit中的諸多註解以及他們的作用。
第一類:網絡請求註解
用於網絡請求方式的註解,比如@GET註解的就是通過get請求接口,@Post註解標記的就是通過post請求接口。類似的是還有@PUT、@DELETE、@HEAD(常用)。作用相同。不多敘述。
當然,在網絡請求註解中有一個特殊註解:@HTTP,這個註解類似於一個融合器,他可以在使用上述請求的同時,並進行擴展配置。比如我們通過@HTTP配置一個Get請求,且配置body,那我們可以這樣配置:
1@HTTP(method = "GET",path = "{user}/repos", hasBody = true)
2Call<List<Repo>> listRepos3(@Path("user") String user);
當然,如果不知道如何使用,直接點到HTTP接口的源碼中查看,注釋裡面便有具體使用案例。
第二類:網絡請求標記註解
retrofit中的標記註解有是三個,分別是:@FormUrlEncoded、@Multipart、@Streaming,見名知意,咱們也稍微解釋下作用。
1@FormUrlEncoded
2@POST("user/edit")
3Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
1@POST("/file")
2@Multipart
3Observable<DataResponse<UploadBean>> uploadFile(@Part("file\"; filename=\"aserbao.png\"") RequestBody file,@Part("name") RequestBody nickName);
當然,@Multipart還可以通過@PartMap添加多個上傳信息來實現一次上傳多個文件。比如我們需要上傳aserbao/imgs這個目錄下的所有圖片,我們可以這樣實現。
1@Multipart
2@POST("/files")
3Call<UploadBean> uploadFiles(@PartMap Map<String, RequestBody> params);
4
5String aserbao_path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aserbao/imgs/";
6File file1 = new File(aserbao_path);
7if (!file1.exists()) return;
8Map<String, RequestBody> partMap = new HashMap<>();
9for (File file : file1) {
10 RequestBody fileBody = RequestBody.create(MediaType.parse("image/*"), file);
11 partMap.put("file\"; filename=\"" + file.getName() + "\"", fileBody);
12}
13……
第三類:網絡請求參數註解
這類註解也是使用最多的一類,下面咱們來一起了解下:
1
2@GET("user")
3Call<User> getUser(@Header("Authorization") String authorization)
4
5
6@Headers({
7 "Accept: application/vnd.github.v3.full+json",
8 "User-Agent: Retrofit-Sample-App"
9})
10@GET("users/{username}")
11Call<User> getUser(@Path("username") String username);
12
13
14@GET("user")
15Call<User> getUser(@HeaderMap Map<String, String> headers)
1@POST("users/new")
2Call<User> createUser(@Body User user);
值得注意的是,當沒有添加轉換器的使用,@Body注釋的對象只能是RequestBody。
1@FormUrlEncoded
2@POST("user/edit")
3Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
@Part,@PartMap: 這兩個方法用在發POST/PUT請求時提交欄位,和@Field,@FieldMap的區別在於:@Field,@FieldMap在@@FormUrlEncoded標記的方法內使用,而@Part,@PartMap在@Multipart標記的方法內使用。
1@Multipart
2@PUT("user/photo")
3Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
1@GET("users/{user}/repos")
2Call<List<Repo>> listRepos(@Path("user") String user);
這裡當我們調用方法listRepos("aserbao")時,對應@GET中的values值就會變成users/aserbao/repos
1@GET("/user/test")
2Call<Test> testQuery(@Query("id") String id);
調用testQuery(15),對應生成@GET中的values就是/user/test?id=15
1@GET("https://api.github.com/users/aserbao/repos")
2 Call<List<Repo>> listAbsRepos();
3
4@GET
5Call<List<Repo>> listAbsRepos(@Url String url);
Retfoit的註解有一個value的參數,比如@GET("users/{user}/repos")。當然不同的baseUrl配置,value參數起的作用也是不同的。
繼續拿上面例子來說,比如我們要請求https://api.github.com/users/aserbao/repos這個url,我們可以怎麼配置呢?
第一種:baseUrl中只添加host也就是https://api.github.com/,後面的參數寫在@GET註解裡。
這裡直接拿上面的例子中的代碼就可以了。
1new Retrofit.Builder()
2 .baseUrl("https://api.github.com/")
3 .build()
4 .create(IGitHubService.class)
5 .listRepos("aserbao");
6
7@GET("users/{user}/repos")
8Call<List<Repo>> listRepos(@Path("user") String user);
第二種:我們在baseUrl中添加https://api.github.com/users/,後面的參數添加到values裡面也可以。
1new Retrofit.Builder()
2 .baseUrl("https://api.github.com/users/")
3 .build()
4 .create(IGitHubService.class)
5 .listRepos("aserbao");
6
7@GET("{user}/repos")
8Call<List<Repo>> listRepos2(@Path("user") String user);
第三種:我們可以直接將請求連結放到參數裡面。,
1new Retrofit.Builder()
2 .baseUrl("")
3 .build()
4 .create(IGitHubService.class)
5 .listAbsRepos();
6
7@GET("https://api.github.com/users/aserbao/repos")
8Call<List<Repo>> listAbsRepos();
上面三種情況,在實際項目開發過程中我們使用的較多的還是第一種。
特別注意:baseUrl中添加的連結最後必須要添加/符號,否則會報java.lang.IllegalArgumentException: baseUrl must end in / 的異常。
如何給Retrofit設置攔截器?在請求的時候給設置請求攔截器是很有必要的一步,不僅可以讓我們清楚的了解請求內容,快速定位請求過程中遇到的問題。還可以通過攔截請求添加通用參數和頭部欄位。
那如何給Retrofit設置請求攔截器呢?前面也說了Retofit實際上市Okhttp的高度封裝,Okhttp如何設置,Retrofit就怎麼配置即可。當然,有興趣想了解更多關於Okhttp的內容可以參考我的另外一篇文章HTTP 網絡請求庫 OkHttp 的全面講解。
好了,話不多說,咱們來看Retrofit如何設置攔截器。
步驟如下:
1class LoggingInterceptor implements Interceptor {
2 @Override public okhttp3.Response intercept(Chain chain) throws IOException {
3 Request request = chain.request();
4 long t1 = System.nanoTime();
5 Log.e(TAG, String.format("Sending request %s on %s%n%s",
6 request.url(), chain.connection(), request.headers()));
7 okhttp3.Response response = chain.proceed(request);
8 long t2 = System.nanoTime();
9 Log.e(TAG, String.format("Received response for %s in %.1fms%n%s",
10 response.request().url(), (t2 - t1) / 1e6d, response.headers()));
11 return response;
12 }
13}
1OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS)
2
3 .addInterceptor(new LoggingInterceptor())
4 .writeTimeout(20, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS)
5 .build();
1Retrofit retrofit = new Retrofit.Builder()
2 .baseUrl("https://api.github.com/")
3 .baseUrl("https://api.github.com/users")
4 .addConverterFactory(GsonConverterFactory.create())
5 .client(okHttpClient)
6 .build();
通過上面的列子,我們來看下請求運行後的攔截效果:
111-24 10:05:12.023 4671-4690/com.example.baseandroidframework E/RetrofitActivity: Received response for https://api.github.com/users/aserbao/repos in 2495.2ms
2 Date: Tue, 26 Nov 2019 01:36:31 GMT
3 Content-Type: application/json; charset=utf-8
4 Transfer-Encoding: chunked
5 Server: GitHub.com
6 Status: 200 OK
7 X-RateLimit-Limit: 60
8 X-RateLimit-Remaining: 59
9 X-RateLimit-Reset: 1574735790
10 Cache-Control: public, max-age=60, s-maxage=60
11 Vary: Accept
12 ETag: W/"58bffa073ed17b36ffb324dd04f66539"
13 X-GitHub-Media-Type: github.v3; format=json
14 Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type
15 Access-Control-Allow-Origin: *
16 Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
17 X-Frame-Options: deny
18 X-Content-Type-Options: nosniff
19 X-XSS-Protection: 1; mode=block
20 Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
21 Content-Security-Policy: default-src 'none'
22 Vary: Accept-Encoding
23 X-GitHub-Request-Id: D99C:7F00:4DADB:61266:5DDC819D
好了,大功告成,我們配置攔截器就這樣完成了。
總結首先和大家一起來回顧下這篇文章的大致內容,主要講了關於Retrofit的三個方面的內容,分別是:
什麼是Retrofit?為什麼要用Retrofit?如何使用Retrofit?
Retrofit的常用註解以及使用場景。
講了如何給Retrofit設置攔截器。
其實通過文章我們可以發現RetrofitAPI並不多,正如官方所言,他是一個關於OkHttp的高度封裝庫。
---END---