合适的就是好的
在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