編輯:關於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") ListgroupList(@Path("id") int groupId);
也可以添加查詢參數
@GET("group/{id}/users") ListgroupList(@Path("id") int groupId, @Query("sort") String sort);
復雜的查詢參數可以使用Map進行組合
@GET("group/{id}/users") ListgroupList(@Path("id") int groupId, @QueryMap Map options);
請求體
可以通過@Body注解指定一個對象作為Http請求的請求體
@POST("users/new") CallcreateUser(@Body User user);
該對象將會被Retroofit實例指定的轉換器轉換,如果沒有添加轉換器,則只有RequestBody可用。(轉換器的添加在後面介紹)
FORM ENCODED 和 MULTIPART
函數也可以聲明為發送form-encoded和multipart數據。
當函數有@FormUrlEncoded注解的時候,將會發送form-encoded數據,每個鍵-值對都要被含有名字的@Field注解和提供值的對象所標注
@FormUrlEncoded @POST("user/edit") CallupdateUser(@Field("first_name") String first, @Field("last_name") String last);
當函數有@Multipart注解的時候,將會發送multipart數據,Parts都使用@Part注解進行聲明
@Multipart @PUT("user/photo") CallupdateUser(@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") CallgetUser(@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(Callbackcb); }
但是在Retrofit 2.0上,只能定義一個模式,因此要簡單得多。
import retrofit.Call; /* Retrofit 2.0 */ public interface APIService { @POST("/list") CallloadRepo(); }
而創建service 的方法也變得和OkHttp的模式一模一樣。如果要調用同步請求,只需調用execute;而發起一個異步請求則是調用enqueue。
同步請求
// Synchronous Call in Retrofit 2.0 Callcall = service.loadRepo(); Repo repo = call.execute();
以上的代碼會阻塞線程,因此你不能在安卓的主線程中調用,不然會面臨NetworkOnMainThreadException。如果你想調用execute方法,請在後台線程執行。
異步請求
// Synchronous Call in Retrofit 2.0 Callcall = 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") CallloadUsers(); } 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") CallloadSpecialUsers(); }
這種情況下Base URL會被忽略。
可以看到在URL的處理方式上發生了很大變化。它和前面的版本完全不同。如果你想把代碼遷移到Retrofit 2.0,別忘了修正URL部分的代碼。
現在需要OkHttp的支持
OkHttp 在Retrofit 1.9裡是可選的。如果你想讓Retrofit 使用OkHttp 作為HTTP 連接接口,你需要手動包含okhttp 依賴。
但是在Retrofit 2.0中,OkHttp 是必須的,並且自動設置為了依賴。下面的代碼是從Retrofit 2.0的pom文件中抓取的。你不需要再做任何事情了。
http://blog.csdn.net/walid1992/article/details/... com.squareup.okhttp okhttp
為了讓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())添加到鏈表中。
Observableobservable = 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,盡快使用最新版本。
一、EasyTouch插件介紹本文總結時,目前網上可以很方便的下載到EasyTouch4.3版本(額……你懂什麼叫很方便的),由於某些版本和版
所謂的嵌套布局就是在一個文件中嵌套多個布局文件 <frameLayout android:layout_width=match_parent
前些天有個大神告訴我,你寫這麼多TetxtView實際上就實現了一個TextView的功能。我說我要設置background,textsize,textcolor阿,還有
Android開源框架庫分類,挑選出最常用,最實用的開源項目,本篇主要介紹的是優秀開源框架庫和項目,UI個性化控件會獨立介紹。UI個性化控件Dependency Inje