Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Retrofit 2.0:迄今為止最大的更新最好的Android HTTP客戶端庫

Retrofit 2.0:迄今為止最大的更新最好的Android HTTP客戶端庫

編輯:關於Android編程

前言

來自移動支付公司square公司的作品,開源世界top5的最小公司,首先我自己是一個忠實廣場粉,okhttp、picasso、greendao、okio等等~
據Square CTO Bob Lee的說法,Square已經將超過60個項目提交到開源社區,貢獻了25萬行左右的代碼。

原文:Retrofit 2.0: The biggest update yet on the best HTTP Client Library for Android

因為其簡單與出色的性能,Retrofit 是安卓上最流行的HTTP Client庫之一。

不過它的缺點是在Retrofit 1.x中沒有直接取消正在進行中任務的方法。如果你想做這件事必須手動殺死,而這並不好實現。Square幾年前曾許諾這個功能將在Retrofit 2.0實現,但是幾年過去了仍然沒有在這個問題上有所更新。

API 聲明

接口函數的注解和參數表明如何去處理請求
請求方法

每一個函數都必須有提供請求方式和相對URL的Http注解,Retrofit提供了5種內置的注解:GET、POST、PUT、DELETE和HEAD,在注解中指定的資源的相對URL

@GET("users/list")

也可以在URL中指定查詢參數

@GET("users/list?sort=desc")

URL處理

請求的URL可以在函數中使用替換塊和參數進行動態更新,替換塊是{ and }包圍的字母數字組成的字符串,相應的參數必須使用相同的字符串被@Path進行注釋

@GET("group/{id}/users")
List groupList(@Path("id") int groupId);

也可以添加查詢參數

@GET("group/{id}/users")
List groupList(@Path("id") int groupId, @Query("sort") String sort);

復雜的查詢參數可以使用Map進行組合

@GET("group/{id}/users")
List groupList(@Path("id") int groupId, @QueryMap Map options);

請求體

可以通過@Body注解指定一個對象作為Http請求的請求體

@POST("users/new")
Call createUser(@Body User user);

該對象將會被Retroofit實例指定的轉換器轉換,如果沒有添加轉換器,則只有RequestBody可用。(轉換器的添加在後面介紹)
FORM ENCODED 和 MULTIPART

函數也可以聲明為發送form-encoded和multipart數據。
當函數有@FormUrlEncoded注解的時候,將會發送form-encoded數據,每個鍵-值對都要被含有名字的@Field注解和提供值的對象所標注

@FormUrlEncoded
@POST("user/edit")
Call updateUser(@Field("first_name") String first, @Field("last_name") String last);

當函數有@Multipart注解的時候,將會發送multipart數據,Parts都使用@Part注解進行聲明

@Multipart
@PUT("user/photo")
Call updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

Multipart parts要使用Retrofit的眾多轉換器之一或者實現RequestBody來處理自己的序列化。
Header處理

可以使用@Headers注解給函數設置靜態的header

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call> widgetList();

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

需要注意的是:header不能被互相覆蓋。所有具有相同名字的header將會被包含到請求中。

可以使用@Header注解動態的更新一個請求的header。必須給@Header提供相應的參數,如果參數的值為空header將會被忽略,否則就調用參數值的toString()方法並使用返回結果

@GET("user")
Call getUser(@Header("Authorization") String authorization)

使用OkHttp攔截器可以指定需要的header給每一個Http請求

OkHttpClient client = new OkHttpClient();
client.networkInterceptors().add(new Interceptor() {
    @Override
    public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
        com.squareup.okhttp.Response response = chain.proceed(chain.request());
        // Do anything with response here

        return response;
    }
});
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(BASE_URL)
        http://blog.csdn.net/walid1992/article/details/...
        .client(client)
        .build();

新的Service定義方式,不再有同步和異步之分
關於在Retrofit 1.9中service 接口的定義,如果你想定義一個同步的函數,你應該這樣定義:

/* Synchronous in Retrofit 1.9 */

public interface APIService {

    @POST("/list")
    Repo loadRepo();

}

而定義一個異步的則是這樣:

/* Asynchronous in Retrofit 1.9 */

public interface APIService {

    @POST("/list")
    void loadRepo(Callback cb);

}

但是在Retrofit 2.0上,只能定義一個模式,因此要簡單得多。

import retrofit.Call;

/* Retrofit 2.0 */

public interface APIService {

    @POST("/list")
    Call loadRepo();

}

而創建service 的方法也變得和OkHttp的模式一模一樣。如果要調用同步請求,只需調用execute;而發起一個異步請求則是調用enqueue。

同步請求

// Synchronous Call in Retrofit 2.0

Call call = service.loadRepo();
Repo repo = call.execute();

以上的代碼會阻塞線程,因此你不能在安卓的主線程中調用,不然會面臨NetworkOnMainThreadException。如果你想調用execute方法,請在後台線程執行。

異步請求

// Synchronous Call in Retrofit 2.0

Call call = service.loadRepo();
call.enqueue(new Callback() {
    @Override
    public void onResponse(Response response) {
        // Get result Repo from response.body()
    }

    @Override
    public void onFailure(Throwable t) {

    }
});

以上代碼發起了一個在後台線程的請求並從response 的response.body()方法中獲取一個結果對象。注意這裡的onResponse和onFailure方法是在主線程中調用的。

我建議你使用enqueue,它最符合 Android OS的習慣。

取消正在進行中的業務
service 的模式變成Call的形式的原因是為了讓正在進行的事務可以被取消。要做到這點,你只需調用call.cancel()。

call.cancel();
事務將會在之後立即被取消。好簡單嘿嘿!

Converter現在從Retrofit中刪除
在Retrofit 1.9中,GsonConverter 包含在了package 中而且自動在RestAdapter創建的時候被初始化。這樣來自服務器的son結果會自動解析成定義好了的Data Access Object(DAO)

但是在Retrofit 2.0中,Converter 不再包含在package 中了。你需要自己插入一個Converter 不然的話Retrofit 只能接收字符串結果。同樣的,Retrofit 2.0也不再依賴於Gson 。

如果你想接收json 結果並解析成DAO,你必須把Gson Converter 作為一個獨立的依賴添加進來。

compile 'com.squareup.retrofit:converter-gson:2.0.0-beta1'

然後使用addConverterFactory把它添加進來。注意RestAdapter的別名仍然為Retrofit。

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.nuuneoi.com/base/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();

service = retrofit.create(APIService.class);

這裡是Square提供的官方Converter modules列表。選擇一個最滿足你需求的。

Gson: com.squareup.retrofit:converter-gson
Jackson: com.squareup.retrofit:converter-jackson
Moshi: com.squareup.retrofit:converter-moshi
Protobuf: com.squareup.retrofit:converter-protobuf
Wire: com.squareup.retrofit:converter-wire
Simple XML: com.squareup.retrofit:converter-simplexml

你也可以通過實現Converter.Factory接口來創建一個自定義的converter 。

我比較贊同這種新的模式。它讓Retrofit對自己要做的事情看起來更清晰。

自定義Gson對象
為了以防你需要調整json裡面的一些格式,比如,Date Format。你可以創建一個Gson 對象並把它傳遞給GsonConverterFactory.create()。

Gson gson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
        .create();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.nuuneoi.com/base/")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

service = retrofit.create(APIService.class);

完成。

新的URL定義方式
Retrofit 2.0使用了新的URL定義方式。

1、ps:貌似第二個才符合習慣。

對於 Retrofit 2.0中新的URL定義方式,這裡是我的建議:

Base URL: 總是以 /結尾

@Url: 不要以 / 開頭

比如

public interface APIService {

    @POST("user/list")
    Call loadUsers();

}

public void doSomething() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://api.nuuneoi.com/base/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    APIService service = retrofit.create(APIService.class);
}

以上代碼中的loadUsers會從 http://api.nuuneoi.com/base/user/list獲取數據。

而且在Retrofit 2.0中我們還可以在@Url裡面定義完整的URL:

public interface APIService {

    @POST("http://api.nuuneoi.com/special/user/list")
    Call loadSpecialUsers();

}

這種情況下Base URL會被忽略。

可以看到在URL的處理方式上發生了很大變化。它和前面的版本完全不同。如果你想把代碼遷移到Retrofit 2.0,別忘了修正URL部分的代碼。

現在需要OkHttp的支持
OkHttp 在Retrofit 1.9裡是可選的。如果你想讓Retrofit 使用OkHttp 作為HTTP 連接接口,你需要手動包含okhttp 依賴。

但是在Retrofit 2.0中,OkHttp 是必須的,並且自動設置為了依賴。下面的代碼是從Retrofit 2.0的pom文件中抓取的。你不需要再做任何事情了。


  
    com.squareup.okhttp
    okhttp
  

  http://blog.csdn.net/walid1992/article/details/...

為了讓OkHttp 的Call模式成為可能,在Retrofit 2.0中OkHttp 自動被用作HTTP 接口。

即使response存在問題onResponse依然被調用
在Retrofit 1.9中,如果獲取的 response 不能背解析成定義好的對象,則會調用failure。但是在Retrofit 2.0中,不管 response 是否能被解析。onResponse總是會被調用。但是在結果不能被解析的情況下,response.body()會返回null。別忘了處理這種情況。

如果response存在什麼問題,比如404什麼的,onResponse也會被調用。你可以從response.errorBody().string()中獲取錯誤信息的主體。

Response/Failure 邏輯和Retrofit 1.9差別很大。如果你決定遷移到Retrofit 2.0,注意小心謹慎的處理這些情況。

缺少INTERNET權限會導致SecurityException異常
在Retrofit 1.9中,如果你忘記在AndroidManifest.xml文件中添加INTERNET權限。異步請求會直接進入failure回調方法,得到PERMISSION DENIED 錯誤消息。沒有任何異常被拋出。

但是在Retrofit 2.0中,當你調用call.enqueue或者call.execute,將立即拋出SecurityException,如果你不使用try-catch會導致崩潰。

這類似於在手動調用HttpURLConnection時候的行為。不過這不是什麼大問題,因為當INTERNET權限添加到了 AndroidManifest.xml中就沒有什麼需要考慮的了。

Use an Interceptor from OkHttp
在Retrofit 1.9中,你可以使用RequestInterceptor來攔截一個請求,但是它已經從Retrofit 2.0 移除了,因為HTTP連接層已經轉為OkHttp。

結果就是,現在我們必須轉而使用OkHttp裡面的Interceptor。首先你需要使用Interceptor創建一個OkHttpClient對象,如下:

OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());

        // Do anything with response here

        return response;
    }
});

然後傳遞創建的client到Retrofit的Builder鏈中。

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.nuuneoi.com/base/")
        .addConverterFactory(GsonConverterFactory.create())
        .client(client)
        .build();

以上為全部內容。

學習關於OkHttp Interceptor的知識,請到OkHttp Interceptors。

RxJava Integration with CallAdapter
除了使用Call模式來定義接口,我們也可以定義自己的type,比如MyCall。。我們把Retrofit 2.0的這個機制稱為CallAdapter。

Retrofit團隊有已經准備好了的CallAdapter module。其中最著名的module可能是為RxJava准備的CallAdapter,它將作為Observable返回。要使用它,你的項目依賴中必須包含兩個modules。

compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
compile 'io.reactivex:rxandroid:1.0.1'

Sync Gradle並在Retrofit Builder鏈表中如下調用addCallAdapterFactory:

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.nuuneoi.com/base/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

你的Service接口現在可以作為Observable返回了!

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.nuuneoi.com/base/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

你可以完全像RxJava那樣使用它,如果你想讓subscribe部分的代碼在主線程被調用,需要把observeOn(AndroidSchedulers.mainThread())添加到鏈表中。

Observable observable = service.loadDessertListRx();

observable.observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber() {
        @Override
        public void onCompleted() {
            Toast.makeText(getApplicationContext(),
                    "Completed",
                    Toast.LENGTH_SHORT)
                .show();
        }

        @Override
        public void onError(Throwable e) {
            Toast.makeText(getApplicationContext(),
                    e.getMessage(),
                    Toast.LENGTH_SHORT)
                .show();
        }

        @Override
        public void onNext(DessertItemCollectionDao dessertItemCollectionDao) {
            Toast.makeText(getApplicationContext(),
                    dessertItemCollectionDao.getData().get(0).getName(),
                    Toast.LENGTH_SHORT)
                .show();
        }
    });

完成!我相信RxJava的粉絲對這個變化相當滿意。

總結
還有許多其他變化,你可以在官方的Change Log 中獲取更多詳情。不過,我相信我已經在本文涵蓋了主要的issues。

你可能會好奇現在是否是切換到Retrofit 2.0 的時機?考慮到它仍然是beta階段,你可能會希望繼續停留在1.9除非你跟我一樣是一個喜歡嘗鮮的人。 Retrofit 2.0用起來很好據我的經驗來看還沒有發現bug。

注意Retrofit 1.9 的官方文檔現在已經從Square的github主頁刪除。我建議你現在就開始學習Retrofit 2.0,盡快使用最新版本。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved