Retrofit2.0起步篇

retrofit 英文名字是改裝的意思,也就是說他是對網絡請求的一種改裝,他不負責進行網絡請求,他是對請求方式的一種封裝。真正進行網絡請求的是okhttp。
如下全部內容在Android Studio已經導入retrofit爲基礎。導入方式以下:html

compile 'com.squareup.retrofit2:retrofit:2.1.0'
  compile 'com.squareup.retrofit2:converter-gson:2.1.0'
  compile 'com.squareup.retrofit2:converter-scalars:2.1.0'

利用Retrofit進行簡單的GET請求

retrofit在構建請求方式以前,須要構建一個接口方法,經過這個接口方法的返回值,來進行網絡請求。
下面,來經過一些簡單的例子瞭解GET請求。json

實驗一:對一個簡單的html頁面進行GET請求

咱們要獲取百度頁面的HTML。首先構建以下接口:api

public interface HtmlService {
    @GET("/")
    Call<String> getHtml();
}

注意,GET註解中的參數,和方法中的參數至少要加一個,不然會報錯。因爲,咱們只須要請求www.baidu.com,因此get這裏不須要加參數,就是/
而後,咱們經過以下步驟,來進行網絡請求。
在咱們須要進行網絡請求的類中,經過如下的步驟,進行網絡請求:cookie

  1. 構建retrofit對象。
  2. 動態代理生成接口的對象。
  3. 經過接口的方法,獲得要請求的API的調用。
  4. 經過同步/異步的方式,獲得response。
  5. 根據須要,處理response。

第一步網絡

Retrofit retrofit = new Retrofit.Builder().          addConverterFactory(ScalarsConverterFactory.create()).
                baseUrl("https://www.baidu.com").
                build();

經過以上代碼,能夠簡單的構建一個retrofit對象,addConverterFactory是對response進行解析,裏面添加的參數是表示對response用String解析,而後添加一個基礎的URL,後續的參數則是經過上面咱們定製的接口來添加,最後構建一個完整的URL。
第二步app

HtmlService htmlService = retrofit.create(HtmlService.class);

經過動態代理,生成一個接口的對象。異步

第三步ide

Call<String> call = htmlService.getHtml();

經過接口的方法獲得調用的對象。post

第四步與第五步
異步方法獲得response:ui

call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                showText.append(response.body());
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Toast.makeText(MainActivity.this,t.getMessage(),Toast.LENGTH_SHORT).show();
            }
        });

獲得的response,經過response.body()獲得響應報文的body部分。
同步方法獲得response:

new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    final String str = call.execute().body();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            showText.append(str);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

實驗二:對一個返回JSON格式的API進行GET請求

經過GET請求GankIO的api獲得Json:
首先,咱們也是經過接口,構建一個接口方法:

@GET("content/{number}/{page}")
Call<HistoryBean> getHistoryData(@Path("number") String number,@Path("page") String page);

這裏,方法裏面傳入的參數會放到@GET的註解裏面。
而後,從新構建一個retrofit對象:

Retrofit retrofit = new Retrofit.Builder().
              addConverterFactory(GsonConverterFactory.create()).
                baseUrl("http://gank.io/api/history/").
                build();

這裏面添加的解析器是GsonConverterFactory,表示對response中body提供對象解析。而後的方法和上面相似:

HtmlService htmlService = retrofit.create(HtmlService.class);
        call = htmlService.getHistoryData("2", "1");
call.enqueue(new Callback<HistoryBean>() {
            @Override
            public void onResponse(Call<HistoryBean> call, Response<HistoryBean> response) {
                HistoryBean hb = response.body();
                if(hb == null) return;
                showText.append(hb.isError() + "");
                for(HistoryBean.ResultsBean rb : hb.getResults()){
                    showText.append(rb.getTitle() + "/n");
                }
            }

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

            }
        });

上面的方法是異步獲得的,同步的方法和上面相似,就很少說了。

實驗三:添加一個請求參數構建GET請求

上面的GET方法是沒有查詢參數的,下面對一個有查詢參數的api,進行GET請求,這裏咱們利用豆瓣的搜索圖書的API
這個API接受4個搜索參數,具體以下:

參數 意義 備註
q 查詢關鍵字 q與tag必傳其一
tag 查詢的tag q與tag必傳其一
start 取結果的offset 默認爲0
count 取結果的條數 默認爲20

首先,咱們也是構建一個請求接口的方法:

@GET("book/search")
Call<BookBean> queryBookInfo(@Query("q") String name);

在這裏面,咱們用到了一個新的註解參數@Query 這個參數表示請求參數會以鍵值對的形式拼接在URL後面。
這樣的方式,有一種侷限性,由於要在每一個GET接口方法裏面寫入鍵值對信息,若是,有些鍵值對信息是每一個GET方法都須要的,咱們就會經過一個攔截器的形式,統一在請求的時候加上。步驟以下:

  1. 自定義一個攔截器實現Interceptor
  2. 建立retrofit的客戶端(上面的代碼都是默認的客戶端),加上這個攔截器。

第一步

public class CustomInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl httpUrl = request.url().newBuilder()
                .addQueryParameter("token", "tokenValue")
                .build();
        request = request.newBuilder().url(httpUrl).build();
        return chain.proceed(request);
    }
}

第二步

OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().
                addInterceptor(new CustomInterceptor()).
                connectTimeout(1000, TimeUnit.MILLISECONDS);
        
Retrofit retrofit = new Retrofit.Builder().
                client(httpClientBuilder.build()).
                addConverterFactory(GsonConverterFactory.create()).
                baseUrl("https://api.douban.com/v2/").
                build();
HtmlService htmlService = retrofit.create(HtmlService.class);
call = htmlService.queryBookInfo("第一行代碼");

後續的異步請求基本一致,就不細說了。

實驗四:添加多種請求參數構建GET請求

實驗三的部分,講了對一個查詢參數和一個共有的查詢參數的GET請求構建方法,下面多個查詢參數的GET請求,看看是否有簡單的方式,由於不想在一個方法裏,傳入4個以上的參數。
請求的API仍是上邊的豆瓣的搜索API,他正好有4個請求參數
下面,看以下構建方式:

@GET("book/search")
Call<BookBean> queryBookInfo(@QueryMap Map<String,String> options);

而後,將請求參數經過鍵值對的形式保存到Map裏:

Map<String,String> options = new HashMap<>();
 options.put("q","第一行代碼");
 options.put("start","0");
 options.put("count","1");
 call = htmlService.queryBookInfo(options);

在上面的狀況下,有多種鍵值對,每一種key對應的value都是惟一的,retrofit也支持相同的key,卻有多種value的形式。方式以下:

@GET("book/search")
Call<BookBean> queryBookInfo(@Query("key") List<String> value);

而後,將value的集合傳入方法中,後續的步驟不變,就很少數。

利用Retrofit進行簡單的POST請求

利用retorfit進行post請求與進行get請求沒有太多的區別。主要的區別就在構建接口方法上面,有一些不一樣,下面經過一些實驗來看一下具體的區別。

實驗一:將少數參數放到請求體中進行POST請求

下面的POST方法API是我本身寫的後臺來接受簡單的POST,就不放出來了。
首先,也是構建一個接口方法:

@FormUrlEncoded
@POST("login")
Call<String> doLogin(@Field("name")String name,@Field("password") String password);

第一個註解,表示自動將請求參數的類型調整爲application/x-www-form-urlencoded ,若是方法參數的註解用了@Field 就必定要用@FormUrlEncoded。POST註解裏面依舊放的是API,方法參數經過@Field將請求參數放置在請求體中。
後續建立retrofit對象,建立call對象,發起請求,都是和GET方法同樣,就很少說了。

實驗二:將多個參數放到請求體中進行POST請求

這個只不過構建接口方法的時候,有所區別,其餘步驟和多種參數進行GET請求同樣。

@FormUrlEncoded
@POST("login")
Call<String> doLogin(@FieldMap Map<String,String> fields);

將多個請求參數保存到Map中,傳入方法中,沒什麼好說的。

實驗三:利用POST進行文件上傳

一樣構建一個接口方法:

@Multipart
@POST("upload")
Call<ResponseBody> uploadFile(@Part("description") RequestBody description,
@Part MultipartBody.Part file);

這裏的POST修飾註解就換成了@Multipart ,在方法參數裏面,經過@Part註解來修飾參數。
咱們說一下具體怎麼構建這些方法的參數。
首先,構建一個RequestBody對象的description,構建方式以下:

RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), "這是一個文件");

而後,構建一個MultipartBody.Part對象的file,不過在構建以前,先要建立一個RequestBody對象,經過這個對象才能建立一個MultipartBody.Part對象。代碼以下:

RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"),file);
MultipartBody.Part body = MultipartBody.Part.createFormData("file",file.getName(),requestBody);

而後和其餘方法同樣,利用這些對象,生成call,而後進行網絡請求。

call = service.uploadFile(description,body);

固然,retrofit支持多種上傳圖片的方式,其構建方式以下:

// 上傳多個文件
    @Multipart
    @POST("upload")
    Call<ResponseBody> uploadMultipleFiles(
            @Part("description") RequestBody description,
            @Part MultipartBody.Part file1,
            @Part MultipartBody.Part file2);

以上這些實驗就是利用Retrofit實現簡單POST 請求。

添加HEADER

咱們在進行復雜的網絡請求的時候,一般要對請求添加頭部,retrofit提供了多種添加方式,能夠分爲以下兩種:

  1. 靜態添加頭部
  2. 動態添加頭部

靜態添加頭部

靜態添加頭部,則每次請求的時候,頭部的信息都是固定的,不能夠更改的。添加靜態頭部的方式也有多種,方法以下:

  1. 在接口中添加。
  2. 經過攔截器添加。

下面,咱們分別說一說每一種。
在接口中添加
仍是以上文寫到的接口爲例,添加Cache-Control,User-Agent請求頭部。

@Headers({
            "Cache-Control: max-age=640000",
            "User-Agent: app-name"
    })

經過攔截器添加
和上面統一處理GET參數的定製器同樣,一樣實現Interceptor,代碼以下:

public class RequestInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request request = original.newBuilder()
                .header("User-Agent", "app-name")
                .header("Cache-Control", "max-age=640000")
                .method(original.method(), original.body())
                .build();
        return chain.proceed(request);
    }
}

而後,在建立okHttp的客戶端時,把攔截器加進去,建立retrofit對象時,指定該客戶端便可。

OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().
                addInterceptor(new CustomInterceptor()).
                addInterceptor(new RequestInterceptor()).
                connectTimeout(1000, TimeUnit.MILLISECONDS);

動態添加頭部

動態添加的好處,就在於不一樣的請求會有不一樣的請求頭部,那麼可想而知,其添加的部分就是在接口方法裏面。

@GET("{number}/{page}")
Call<HistoryBean> getHistoryData(@Header("Content-Range") String contentRange ,@Path("number") String number, @Path("page") String page);

後續的使用都是同樣的,沒什麼好說的。

設置網絡請求日誌

retrofit提供了對網絡請求的過程進行打印的日誌的插件,須要單獨的導入,其方式以下:

compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

經過上面的導入代碼,能夠看出這個日誌插件是okHttp特有的,這也能夠證實,retrofit只是封裝了請求的方式,真正請求的仍是經過okHttp。那麼咱們也能夠猜出,其設置的方式必然也是經過攔截器,放進okHttp的客戶端裏面。具體的代碼以下:

HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().
                addInterceptor(new CustomInterceptor()).
                addInterceptor(new RequestInterceptor()).
                addInterceptor(httpLoggingInterceptor).
                connectTimeout(1000, TimeUnit.MILLISECONDS);

注意上面的代碼,在設置請求級別上面設置爲body,下面說一下具體的級別以及其內涵:

  1. NONE : 沒有任何日誌信息。
  2. Basic : 打印請求類型,URL,請求體大小,返回值狀態以及返回值的大小。
  3. Headers : 打印返回請求和返回值的頭部信息,請求類型,URL以及返回值狀態碼
  4. Body : 打印請求和返回值的頭部和body信息。

總結

上面就是簡單的retrofit的使用,關於利用retrofit結合其餘部分如Rx,okHttp等等,或者利用retrofit實現多種文件上傳,下載功能,保存cookie等等功能,能夠期待後續的文章。

相關文章
相關標籤/搜索