天天看點

Android中使用Retrofit庫進行Http通訊

合适的就是好的

在Anrdoid中,有很多種Http通訊網絡庫可供我們使用,比如Volley, OKHttp和Retrofit等,沒有最好的,隻有最适合的。在不同的場景下,我們會有不同的選擇。

如果隻是單純地從服務端的restful api接口中擷取json格式的資料,相信很多人都會選擇Retrofit,因為其實作起來最簡單,最友善。

但是如果還需要從服務端擷取圖檔,那相信很多人會說Volley會做得更好啊,因為Retrofit沒有現成的接口,而Volley有NetworkImageView或者ImageRequest等,但可能也會有人說,直接用Glide和Picasso會更舒服呀。

如何使用Retrofit

目前都是用Android Studio 來進行開發的,依賴什麼的都是通過 gradle來配置,是以按照以下幾步走:

Gradle配置

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'
           

其中converter-gson,是retrofit2提供的,将Response的Body轉化為json對象的方法,也就是說Retrofit2提供了關于Json的轉化,我們不需要自己再去做這個處理了。

Proguard配置

在導入任何第三方包的時候,我第一個總會去找其Proguard配置是什麼。一般來說,官方提供的文檔中會告訴我們如何使用這些庫,也會提供一段Proguard配置來讓我們在應用中進行配置

#retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
           

在這裡,其實有一點要注意的,-keepattributes Signature,是為了Gson配置的,是因為Gson在轉化Field(字段)的時候會使用到存儲在類中泛型資訊,而Proguard預設會将這些資訊給移除掉,是以我們需要Keep住這些Signature。Signature 是字段,方法和類的簽名資訊,用來辨別其唯一性的。同一個方法,參數不同,如何區分,其實就是靠Signature。

聲明接口 TestService

聲明我們需要與伺服器進行通訊的請求,包括請求類型,請求位址,請求參數,參數的形式等。

public interface TestService {
    @FormUrlEncoded
    @POST("http://ip:port/api/login")
    Call<LoginResult> login(@Field("username") String username,
                            @Field("password") String password);
}
           

注釋 @FormUrlEncoded 指明了請求的内容(content)會使用 form-encoded 的形式,而我們想要傳遞給伺服器的參數,則必須用 @Field 來指定,如上述方法,指定了login方法會指向伺服器的http://ip:port/api/login 接口,請求類型是 Post,指定參數為 username 和 password,而Call 則是Retrofit 定義的一次發送Request并接收Response的一個接口,可以将其看作是一次請求的觸發。

建立Retrofit和TestService對象

Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(SharedPreferenceHelper.getServerHost())
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(buildClient())
                    .build();
 TestService service = retrofit.create(TestService.class);
           

通過Retrofit.Builder.build() 方法,我們可以建立Retrofit對象,再通過Retrofit對象,我們建立TestService對象,進而真正地将 TestService 接口執行個體化。

  • 利用 baseUrl 方法,我們可以指明伺服器位址,比如:
.baseUrl("http://192.168.1.100")
           

則我們指定了伺服器位址為 http://192.168.1.100,這樣,我們在聲明接口TestService的api時,就可以隻聲明路徑,如下:

@FormUrlEncoded
    @POST("/api/login")
    Call<LoginResult> login(@Field("username") String username,
                            @Field("password") String password);
           
  • 利用 addConverterFactory(GsonConverterFactory.create()) 添加 Gson 轉換

這就是我們在 build.gradle中引入的 converter-gson 使用的地方了。

  • 利用 client 方法,我們可以添加一些 Interceptor 來記錄請求的參數,整個請求的時間等。

    如下,我們可以聲明一個LoggingInterceptor,如下:

public class LoggingInterceptor implements Interceptor{

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();
        long t1 = System.nanoTime();
        Logger.v("request:" + request.toString());
        if (request.body() != null) {
            FormBody body = (FormBody) request.body();
            int size = body.size();
            for (int i = ; i < size; i++) {
                Logger.v(body.name(i) + " : " + body.value(i));
            }
        }
        Response response = chain.proceed(request);
        long t2 = System.nanoTime();
        Logger.v(String.format("received " + response.toString() + " in %.1fms%n", (t2 - t1) / d));
        return response;
    }
}
           

在這裡,通過 FormBody(因為我們使用的是 Form-Encoded的方法)來将RequestBody其中的參數和值給列印出來,同樣的,我理所當然地以為,也可以将response.body也可以列印出來,發現可以通過response.body.string() 方法,可以将response的内容給列印出來,比如這樣

if (response.body() != null) {
   Logger.v("response.body: " + response.body().string());
}
           

結果,真的列印出來了,如我所願,然而,踩坑了。

!!,在這裡有個坑,不能使用 response.body.string() 方法, 因為 string() 方法會将response的内容給讀取了,導緻整個請求關閉,這樣在後續操作,就會收到Exception: close了。

定義了 LoggingInterceptor,建立OKHttpClient,如下:

private static OkHttpClient buildClient() {
        OkHttpClient client = new OkHttpClient.Builder()
                .addNetworkInterceptor(new LoggingInterceptor())
                .build();
        return client;
    }
           

再通過 .client(buildClient)方法,設定給Retrofit,達到在TestService調用方法的時候進行攔截。

調用TestService.login方法建立Call,将調用Call的enqueue方法

private void doLogin() {
       Call<LoginResult> call = testService.login("username","password");            
       call.enqueue(new Callback<LoginResult>() {
            @Override
            public void onResponse(Response<LoginResult> response) {
                LoginResult loginResult = response.body();
                //do something about loginResult
            }

            @Override
            public void onFailure(Throwable t) {
                //do something about throwable t
            }
        });
    }
           

通過 call.enqueue方法,将call放進請求隊列裡,并聲明一個Callback,通過callback的onResponse方法和onFailure方法,分别對正常的Response和請求過程中出現的錯誤進行處理。

對Retrofit2的基本使用,到此就結束了。

參考并感謝

高效率http retrofit okhttp

Retrofit

Interceptors

上一篇: http通訊過程