Android 必備知識點 Retrofit的全面講解

2021-03-02 秦子帥
前言

因為之前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);

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---

 創作不易,點個「在看

相關焦點

  • Android開發必備的「80」個開源庫
    你所不知道的Android Studio調試技巧https://www.jianshu.com/p/011eb88f4e0d一份系統、全面的安卓進階學習指南https://github.com/iwannabetop/Awesome-Android-Learning-GuideTrinea - 性能優化系列總篇
  • 這一次,就徹底了解OkHttp與Retrofit吧!
    所以,網絡請求的本質仍舊是OkHttp完成的,retrofit只是幫使用者來進行工作簡化的,比如配置網絡,處理數據等工作,提高這一系列操作的復用性。這也就是網上流行的一個不太準確的總結:OkHttp是瑞士軍刀,retrofit則是將瑞士軍刀包裝成了一個非常好用的指甲鉗。
  • Android MVP+Retrofit+RxJava實踐小結
    真愛,請星標或置頂關於MVP、Retrofit、RxJava,之前已經分別做了分享,如果您還沒有閱讀過,可以猛戳:1、Android MVP 實例:http://wuxiaolong.me/2015/09/23/AndroidMVPSample2、Android Retrofit 2.0使用:http://wuxiaolong.me/2016/01/15/retrofit
  • Retrofit面試總結
    本系列記錄面試過程中各個知識點,而不是入門系列,如果有不懂的自行學習。涉及到的設計模式 外觀模式,構建者模式,工廠模式,代理模式,適配器模式,策略模式,觀察者模式概括 Retrofit就是一個網絡請求框架的封裝,底層的網絡請求默認使用的Okhttp,本身只是簡化了用戶網絡請求的參數配置等,還能與Rxjava相結合,使用起來更加簡潔方便。
  • Retrofit 2.0.0 正式發布,Android 的 REST 客戶端
    Retrofit 2.0.0 正式發布了,retrofit 是一個類型安全的 REST 客戶端,用於 Android 平臺。。
  • Kotlin協程優雅的與Retrofit纏綿
    涉及到Kotlin的協程、擴展方法、DSL,沒有基礎的小夥伴,先去了解這三樣東西,本篇文章不再進行講解。DSL可以看看我寫這篇簡介在網絡請求中,我們需要關注的隱式問題就是:頁面生命周期的綁定,關閉頁面後需要關閉未完成的網絡請求。為此,各位前輩,是八仙過海、各顯神通。我也是從學習、模仿前輩,到自我理解的轉變。1.
  • 2017 年 Android 曲折的求職之路
    自定義 View,偶爾穿插下 retrofit,Rxjava,熱修復神馬的,面完之後就出去了讓你一直等啊等,等了快 40 分鐘的時候進來說總監在開會這個公司真特麼的是個奇葩,你約人的時候不會挑個沒會的時間麼,貌似拉勾上有個面php 的哥們跟我一樣也是被擱置一直等啊等,真是日了狗了!最後來了一句改天複試吧只說還有複試,讓我來我也不會來了。。。
  • Android架構之App組件化方案詳細實踐與總結
    下面的表示debug文件夾中的:<application    android:name="debug.CarApplication"    android:icon="@mipmap/ic_car_launcher"    android:label="@string/car_name"    android:supportsRtl="true"    android
  • 最新Android框架排行榜,上百項資源匯總!
    官網地址 http://square.github.io/retrofit/github   https://github.com/square/retrofit作者:square團隊使用:compile 'com.squareup.retrofit2:retrofit:2.3.0'一句話介紹:okhttp是一款基於
  • Android代碼混淆使用手冊
    android.content.ContentProvider-keep public class * extends android.app.backup.BackupAgentHelper-keep public class * extends android.preference.Preference-keep public class * extends android.view.View
  • 一年級語文漢語拼音知識點講解+專項練習,期末複習必備!請列印
    一年級語文漢語拼音知識點講解+專項練習,期末複習必備!請列印#小學一年級語文學習#對於一年級學生家長來說,幫助孩子在一年級語文學習中培養和提升語文學習興趣,夯實基礎知識是頭等大事,只有將教材上的知識點都熟練掌握了
  • 三年經驗 Android 開發面經總結
    在下2017年畢業,目前從事android開發工作已經3年啦,前段時間剛完成一次跳槽,面試了幾家公司,將一些面試經驗分享給大家,希望對大家有所幫助。簡歷首先是簡歷,一般找一個模板,填寫掌握的技能和項目經歷即可。
  • 從ServiceMethod角度來認識retrofit框架
    對於Android開發者而言,retrofit可以說算是比較實用的網絡請求框架,而且是開源的。那麼,從請求執行的角度,以 interface 中我們定義的方法為起始,解讀 retrofit 的執行流程。
  • Android 開發應該掌握的 Proguard 技巧
    對optimize的描述,在Android中使用該功能是有潛在風險的,並不能保證在所有版本的Dalvik虛擬機上正常運行,該選項默認是關閉的,如果開啟,請做好全面的測試。>-keep class android.support.** {*;}-keep public class * extends android.support.v4.
  • 展開與摺疊新課講解,知識點總結全面,記得備一份
    展開與摺疊新課講解,知識點總結全面,記得備一份上節課老師給大家講了生活中的立體圖形,中考中常考的立體圖形的其中一個知識點就是展開與摺疊,並且這個知識點易學會,這節課我們來學一下這些立體圖形的展開與摺疊,幫你在中考中提高個
  • 三年啦,跳槽成功的Android開發面經總結!
    在下2017年畢業,目前從事android開發工作已經3年啦,前段時間剛完成一次跳槽,面試了幾家公司,將一些面試經驗分享給大家,希望對大家有所幫助。首先是簡歷,一般找一個模板,填寫掌握的技能和項目經歷即可。
  • 如何自學Android, 教大家玩爆Android
    Java知識儲備本知識點不做重點講解: 對於有基礎的同學推薦看《Java編程思想》,鞏固基礎,查漏補全,了解並熟悉更多細節知識點。 對於沒有基礎的同學推薦看一本Java基礎的書籍,看完後可以繼續看《Java編程思想》提升自己。 對於自認為時間很充裕,只要基礎學紮實就好的推薦看《瘋狂Java講義》,這本書真的很厚,但是講解的特別詳細。2.
  • 放蕩不羈SVG講解與實戰——Android高級UI
    ><vector xmlns:android="http://schemas.android.com/apk/res/android"    android:width="xxdp"    android:height="yydp"    android:viewportWidth="xx"    android:viewportHeight="yy
  • 你真的會用Retrofit2嗎?Retrofit2完全教程
    1.1、創建Retrofit實例Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost:4567/") .build();創建Retrofit實例時需要通過Retrofit.Builder,並調用baseUrl方法設置URL。