Android 必備知識點 Retrofit 2.6 使用全面解析

前言

由於以前Android開發第三方庫總結的文章在交流羣分享廣受好評,就有很多朋友讓我推薦對應的功能庫。想着,既然你們都以爲不錯,那也想着順手把本身經常使用的這些功能庫給整理出來,從此要是問我怎麼用,直接甩文章。哈哈哈,想一想都開心。java

本文面向對象:有必定基礎的Android開發者。android

本篇文章大體內容從以下三個方面講進行講解:git

  1. 什麼是Retrofit?爲何要用Retrofit?如何使用Retrofit?
  2. Retrofit的經常使用註解以及使用場景。
  3. 如何給Retrofit設置攔截器。

固然,倘若各位以爲內容寫得很差,本人心態很差,不接受任何批評。仍是那句話:you can you up,no can no ……github

好了,話很少說,今天講Retrofit。小板凳拿好,開始上課。坐後面的朋友請到前面來。json

什麼是Retrofit?

Retrofit,英文翻譯過來是翻新,改進的意思,光看名字很難聯想到他的具體做用,官方給的解釋是:Type-safe HTTP client for Android and Java by Square,翻譯過來就是由Square公司開發的一款針對Android網絡請求的框架,底層是基於OkHttp的。retrofit github地址api

爲何要用Retrofit? Retrofit有什麼優點?

在Android開發過程當中,有不少的網絡請求框架,好比Volley、Async Http Client,咱們爲何要用Retrofit?bash

爲何要用?一個詞描述:方便。使用方便,修改也方便。網絡

Retrofit的優勢:app

  • 請求速度快。
  • 使用簡單。
  • 高度解耦。
  • 支持和Rxjava聯用。
  • 支持GET/POST/PUT/DELETE/HEAD/PATCH協議。

缺點:框架

  • 高度封裝致使擴展性較差

如何使用Retrofit?

導包和權限申請

當前文章編寫時最新版本爲2.6.1。導包時到github去導入最新版本便可。

implementation 'com.squareup.retrofit2:retrofit:2.6.1'

複製代碼

Retrofit有一系列的輔助包,當咱們在導包的時候須要根據咱們的數據返回導入對應的包,不然會報異常: Could not locate ResponseBody converter for ……

好比咱們須要經過Gson轉對象,咱們須要增長以下Gson轉換輔助包:

implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
複製代碼

若是咱們使用了protobuf格式,那咱們須要添加protobuf轉換輔助包:

implementation 'com.squareup.retrofit2:converter-protobuf:2.6.2'
複製代碼

固然,還有不少輔助包:好比guava,jackson,jaxb,moshi,scalars等一系列輔助包,固然,這些在retrofit的retrofit-converters包下都有,有興趣的能夠去深刻了解。這裏也列出來供你們導入。

Gson: compile 'com.squareup.retrofit2:converter-gson:2.6.2'
Jackson: compile 'com.squareup.retrofit2:converter-jackson:2.6.2'
Moshi: compile 'com.squareup.retrofit2:converter-moshi:2.6.2'
Protobuf: compile 'com.squareup.retrofit2:converter-protobuf:2.6.2'
Wire: compile 'com.squareup.retrofit2:converter-wire:2.6.2'
Simple XML: compile 'com.squareup.retrofit2:converter-simplexml:2.6.2'
Scalars (primitives, boxed, and String): compile 'com.squareup.retrofit2:converter-scalars:2.6.2'
複製代碼

導完包以後,我們記得在AndroidManifest.xml中聲明網絡請求權限,添加以下代碼便可申請網絡請求權限。

<uses-permission android:name="android.permission.INTERNET" />
複製代碼

好了,準備工做作完了,開始講使用步驟吧。

Retrofit的使用步驟

這裏咱們直接用官方給的例子來作示範:

  • 第一步:定義接口。
public interface IGitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}
複製代碼
  • 第二步:建立裝換對象。
public class Repo {
    ……//其餘屬性
    private String name;
     public String getName() {
        return name;
    }
}
複製代碼
  • 第三步:構造Retrofit對象。
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
               .addConverterFactory(GsonConverterFactory.create())
                .build();

IGitHubService service = retrofit.create(IGitHubService.class);

Call<List<Repo>> listRepos = service.listRepos("aserbao");

複製代碼
  • 第四步:執行請求。enqueue爲異步,execute爲同步。和OkHttp如出一轍。
listRepos.enqueue(new Callback<List<Repo>>() {
            @Override
            public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
                updateUi(response.body());//返回處理
            }

            @Override
            public void onFailure(Call<List<Repo>> call, Throwable t) {

            }
        });
複製代碼

固然,有一些特殊狀況,這裏也提一下:

當建立裝換對象中的字符不能使用時,咱們可使用annotations註解來解決這個問題。舉一個例子:json返回字段中若返回private屬性,衆所周知private不能在Android中當屬性名,那這時候怎麼辦呢?能夠這樣作:

@com.google.gson.annotations.SerializedName("private")
private boolean privateX;
複製代碼

好了,接下來介紹下Api的使用吧,Api的使用官方介紹也挺詳細的,這裏就做下簡單介紹。

Retrofit 註解

上面使用案例中咱們用了兩個註解,分別是@GET和@Path,他們的做用是什麼呢?是否有其餘註解,接下來我們一塊兒去了解下Retrofit中的諸多註解以及他們的做用。

第一類:網絡請求註解

用於網絡請求方式的註解,好比@GET註解的就是經過get請求接口,@Post註解標記的就是經過post請求接口。相似的是還有@PUT、@DELETE、@HEAD(經常使用)。做用相同。很少敘述。

固然,在網絡請求註解中有一個特殊註解:@HTTP,這個註解相似於一個融合器,他能夠在使用上述請求的同時,並進行擴展配置。好比咱們經過@HTTP配置一個Get請求,且配置body,那咱們能夠這樣配置:

@HTTP(method = "GET",path = "{user}/repos", hasBody = true)
Call<List<Repo>> listRepos3(@Path("user") String user);
複製代碼

固然,若是不知道如何使用,直接點到HTTP接口的源碼中查看,註釋裏面便有具體使用案例。

第二類:網絡請求標記註解 retrofit中的標記註解有是三個,分別是:@FormUrlEncoded、@Multipart、@Streaming,見名知意,我們也稍微解釋下做用。

  • @FormUrlEncoded:當方法被@FormUrlEncoded標記時,表示將發送Form表單的數據。而且每一個鍵值對都用@Field註釋,其中包含名稱和提供值的對象。使用方法以下(這裏偷懶,直接從官方案例):
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
複製代碼
  • @Multipart:能夠將多個請求分開進行處理。使用@Part批註請求內容。這裏舉兩個例子: 好比咱們須要實現上傳文件的同時,還須要傳給後臺一個name字段,這時候咱們方法能夠這樣寫:
@POST("/file")
@Multipart
Observable<DataResponse<UploadBean>> uploadFile(@Part("file\"; filename=\"aserbao.png\"") RequestBody file,@Part("name") RequestBody nickName);
複製代碼

固然,@Multipart還能夠經過@PartMap添加多個上傳信息來實現一次上傳多個文件。好比咱們須要上傳aserbao/imgs這個目錄下的全部圖片,咱們能夠這樣實現。

@Multipart
@POST("/files")
Call<UploadBean> uploadFiles(@PartMap Map<String, RequestBody> params);

String aserbao_path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/aserbao/imgs/";
File file1 = new File(aserbao_path);
if (!file1.exists()) return;
Map<String, RequestBody> partMap = new HashMap<>();
for (File file : file1) {
    RequestBody fileBody = RequestBody.create(MediaType.parse("image/*"), file);
    partMap.put("file\"; filename=\"" + file.getName() + "\"", fileBody);
}
…… 

複製代碼
  • @Streaming:流標記,當咱們在處理下載大文件請求時,一般可使用這個註解進行標記,主要做用是能處理返回的響應體,當咱們寫入存儲文件的時候不須要將返回內容轉換成byte[],能夠直接使用response.body().source()進行寫入。

第三類:網絡請求參數註解

這類註解也是使用最多的一類,下面我們來一塊兒瞭解下:

  • @Header,@Headers:前者用來添加請求頭的,後者用來添加不固定請求頭。區別在於前者做用在參數上,後者做用在方法上。固然,若是多個請求頭設置參數咱們也可使用@HeaderMap。
//@Header做用在參數上
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

//@Headers做用在方法上
@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

//@HeaderMap經過鍵值對的方式給參數添加請求頭
@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)
複製代碼
  • @Body:在POST/PUT請求時,可使用@Body註釋將對象指定爲HTTP請求正文。
@POST("users/new")
Call<User> createUser(@Body User user);
複製代碼

值得注意的是,當沒有添加轉換器的使用,@Body註釋的對象只能是RequestBody。

  • @Field,@FieldMap:用在發POST/PUT請求時提交字段,這兩個方法在@FormUrlEncoded標記的方法內使用,做用是爲發送的表單所提供的鍵值對對象。前者表示當個鍵值對,後者表示多個鍵值對。
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
複製代碼
  • @Part,@PartMap: 這兩個方法用在發POST/PUT請求時提交字段,和@Field,@FieldMap的區別在於:@Field,@FieldMap在@@FormUrlEncoded標記的方法內使用,而@Part,@PartMap在@Multipart標記的方法內使用。
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
複製代碼
  • @Path:用於指定參數替換。
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
複製代碼

這裏當咱們調用方法listRepos("aserbao")時,對應@GET中的values值就會變成users/aserbao/repos

  • @Query,@QueryMap:用於添加查詢參數。前者添加單個,後者以鍵值對的形式添加一個或者多個。
@GET("/user/test")
Call<Test> testQuery(@Query("id") String id);
複製代碼

調用testQuery(15),對應生成@GET中的values就是/user/test?id=15

  • @Url:標記用來傳url的。下面這兩種寫法效果是同樣的。
@GET("https://api.github.com/users/aserbao/repos")
    Call<List<Repo>> listAbsRepos();

@GET
Call<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註解裏。

這裏直接拿上面的例子中的代碼就能夠了。

new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build()
    .create(IGitHubService.class)
    .listRepos("aserbao");
    
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
複製代碼

第二種:咱們在baseUrl中添加https://api.github.com/users/,後面的參數添加到values裏面也能夠。

new Retrofit.Builder()
    .baseUrl("https://api.github.com/users/") //這裏注意最後有添加/。
    .build()
    .create(IGitHubService.class)
    .listRepos("aserbao");

@GET("{user}/repos")
Call<List<Repo>> listRepos2(@Path("user") String user);
複製代碼

第三種:咱們能夠直接將請求連接放到參數裏面。,

new Retrofit.Builder()
    .baseUrl("")//baseUrl裏面能夠填空
    .build()
    .create(IGitHubService.class)
    .listAbsRepos();

@GET("https://api.github.com/users/aserbao/repos")
Call<List<Repo>> listAbsRepos();
複製代碼

上面三種狀況,在實際項目開發過程當中咱們使用的較多的仍是第一種。

特別注意:baseUrl中添加的連接最後必需要添加/符號,不然會報java.lang.IllegalArgumentException: baseUrl must end in / 的異常。

如何給Retrofit設置攔截器?

在請求的時候給設置請求攔截器是頗有必要的一步,不只可讓咱們清楚的瞭解請求內容,快速定位請求過程當中遇到的問題。還能夠經過攔截請求添加通用參數和頭部字段。

那如何給Retrofit設置請求攔截器呢?前面也說了Retofit實際上市Okhttp的高度封裝,Okhttp如何設置,Retrofit就怎麼配置便可。固然,有興趣想了解更多關於Okhttp的內容能夠參考個人另一篇文章HTTP 網絡請求庫 OkHttp 的全面講解

好了,話很少說,我們來看Retrofit如何設置攔截器。

步驟以下:

  • 第一步:建立一個攔截器,這裏咱們打印請求的基本信息。
class LoggingInterceptor implements Interceptor {
    @Override public okhttp3.Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        long t1 = System.nanoTime();
        Log.e(TAG, String.format("Sending request %s on %s%n%s",
                request.url(), chain.connection(), request.headers()));
        okhttp3.Response response = chain.proceed(request);
        long t2 = System.nanoTime();
        Log.e(TAG, String.format("Received response for %s in %.1fms%n%s",
                response.request().url(), (t2 - t1) / 1e6d, response.headers()));
        return response;
    }
}
複製代碼
  • 第二步:建立一個OkHttpClient,並配置攔截器。
OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS)
                //添加OkHttp3的攔截器
                .addInterceptor(new LoggingInterceptor())
                .writeTimeout(20, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS)
                .build();
複製代碼
  • 第三部:經過client方法給Retrofit配飾OkHttpClient。
Retrofit retrofit = new Retrofit.Builder()
          .baseUrl("https://api.github.com/")
        .baseUrl("https://api.github.com/users")
        .addConverterFactory(GsonConverterFactory.create())
        .client(okHttpClient)//配置OkHttpClient
        .build();
複製代碼

經過上面的列子,咱們來看下請求運行後的攔截效果:

11-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
    Date: Tue, 26 Nov 2019 01:36:31 GMT
    Content-Type: application/json; charset=utf-8
    Transfer-Encoding: chunked
    Server: GitHub.com
    Status: 200 OK
    X-RateLimit-Limit: 60
    X-RateLimit-Remaining: 59
    X-RateLimit-Reset: 1574735790
    Cache-Control: public, max-age=60, s-maxage=60
    Vary: Accept
    ETag: W/"58bffa073ed17b36ffb324dd04f66539"
    X-GitHub-Media-Type: github.v3; format=json
    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
    Access-Control-Allow-Origin: *
    Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
    X-Frame-Options: deny
    X-Content-Type-Options: nosniff
    X-XSS-Protection: 1; mode=block
    Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
    Content-Security-Policy: default-src 'none'
    Vary: Accept-Encoding
    X-GitHub-Request-Id: D99C:7F00:4DADB:61266:5DDC819D
複製代碼

好了,大功告成,咱們配置攔截器就這樣完成了。

到這裏,咱們的Retrofit的知識點算告一段落了,下面簡單總結下

總結

首先和你們一塊兒來回顧下這篇文章的大體內容,主要講了關於Retrofit的三個方面的內容,分別是:

  1. 什麼是Retrofit?爲何要用Retrofit?如何使用Retrofit?
  2. Retrofit的經常使用註解以及使用場景。
  3. 講了如何給Retrofit設置攔截器。

其實經過文章咱們能夠發現RetrofitAPI並很少,正如官方所言,他是一個關於OkHttp的高度封裝庫。

好了,文章到這裏就要結束了,若是對本文有什麼疑問或者不理解的地方,歡迎給我留言。固然,若是想系統性學Android,提高Android技術的朋友,能夠關注個人我的公衆號「aserbaocool」,加羣討論,一塊兒學習交流Android。

本文參考連接

相關文章
相關標籤/搜索