不熟悉Retrofit的同學可以先參考這篇文章:Retrofit – Java(Android) 的REST 接口封裝類庫谴供,很適合入門颗味。
因為其簡單與出色的性能,Retrofit 是安卓上最流行的HTTP Client庫之一宇色。
不過它的缺點是在Retrofit 1.x中沒有直接取消正在進行中任務的方法讶请。如果你想做這件事必須手動殺死鸵贬,而這并不好實現(xiàn)俗他。
Square幾年前曾許諾這個功能將在Retrofit 2.0實現(xiàn),但是幾年過去了仍然沒有在這個問題上有所更新阔逼。
直到上周兆衅,Retrofit 2.0 才從候選發(fā)布階段變成Beta 1?,并且公開給所有人嗜浮。在嘗試了之后羡亩,我不得不說自己對新的模式和新的功能印象深刻。有許多改進危融,本文將討論它們畏铆。讓我們開始吧!
包還是那個包只是換了新版本
如果你想在自己的項目中導入Retrofit 2.0吉殃,那么在build.gradle的依賴一節(jié)里面添加這行代碼:
compile'com.squareup.retrofit:retrofit:2.0.0-beta1'
Sync gradle 文件之后你就可以使用Retrofit 2.0了辞居。
新的Service定義方式,不再有同步和異步之分
關于在Retrofit 1.9中service 接口的定義蛋勺,如果你想定義一個同步的函數(shù)瓦灶,你應該這樣定義:
```
publicclassPair{publicObject first;publicObject second;publicPair(){ first =newObject(); second =newObject(); }publicstaticPairmake(Object fir, Object sec){ Pair p =newPair(); p.first = fir; p.second = sec;returnp; }}
```
publicclassPair{publicObject first;publicObject second;publicPair(){ first =newObject(); second =newObject(); }publicstaticPairmake(Object fir, Object sec){ Pair p =newPair(); p.first = fir; p.second = sec;returnp; }}
作者:斯云
鏈接:http://www.reibang.com/p/be23f547fa67
來源:簡書
著作權歸作者所有。商業(yè)轉載請聯(lián)系作者獲得授權抱完,非商業(yè)轉載請注明出處贼陶。
/*?Synchronous?in?Retrofit?1.9?*/
publicinterfaceAPIService{
@POST("/list")
RepoloadRepo();
}
而定義一個異步的則是這樣:
/*?Asynchronous?in?Retrofit?1.9?*/
publicinterfaceAPIService{
@POST("/list")
voidloadRepo(Callbackcb);
}
但是在Retrofit 2.0上,只能定義一個模式巧娱,因此要簡單得多碉怔。
importretrofit.Call;
/*?Retrofit?2.0?*/
publicinterfaceAPIService{
@POST("/list")
CallloadRepo();
}
而創(chuàng)建service 的方法也變得和OkHttp的模式一模一樣。如果要調用同步請求禁添,只需調用execute眨层;而發(fā)起一個異步請求則是調用enqueue。
同步請求
//?Synchronous?Call?in?Retrofit?2.0
Callcall=service.loadRepo();
Reporepo=call.execute();
以上的代碼會阻塞線程上荡,因此你不能在安卓的主線程中調用趴樱,不然會面臨NetworkOnMainThreadException。如果你想調用execute方法酪捡,請在后臺線程執(zhí)行叁征。
異步請求
//?Synchronous?Call?in?Retrofit?2.0
Callcall=service.loadRepo();
call.enqueue(newCallback(){
@Override
publicvoidonResponse(Responseresponse){
//?Get?result?Repo?from?response.body()
}
@Override
publicvoidonFailure(Throwablet){
}
});
以上代碼發(fā)起了一個在后臺線程的請求并從response 的response.body()方法中獲取一個結果對象。注意這里的onResponse和onFailure方法是在主線程中調用的逛薇。
我建議你使用enqueue捺疼,它最符合 Android OS的習慣。
取消正在進行中的業(yè)務
service 的模式變成Call的形式的原因是為了讓正在進行的事務可以被取消永罚。要做到這點啤呼,你只需調用call.cancel()卧秘。
call.cancel();
事務將會在之后立即被取消。好簡單嘿嘿官扣!
Converter現(xiàn)在從Retrofit中刪除
在Retrofit 1.9中翅敌,GsonConverter 包含在了package 中而且自動在RestAdapter創(chuàng)建的時候被初始化。這樣來自服務器的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。
Retrofitretrofit=newRetrofit.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
你也可以通過實現(xiàn)Converter.Factory接口來創(chuàng)建一個自定義的converter 。
我比較贊同這種新的模式婿滓。它讓Retrofit對自己要做的事情看起來更清晰老速。
自定義Gson對象
為了以防你需要調整json里面的一些格式,比如凸主,Date Format橘券。你可以創(chuàng)建一個Gson 對象并把它傳遞給GsonConverterFactory.create()。
Gsongson=newGsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
Retrofitretrofit=newRetrofit.Builder()
.baseUrl("http://api.nuuneoi.com/base/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
service=retrofit.create(APIService.class);
完成卿吐。
新的URL定義方式
Retrofit 2.0使用了新的URL定義方式旁舰。Base URL與@Url 不是簡單的組合在一起而是和的處理方式一致。用下面的幾個例子闡明嗡官。
ps:貌似第二個才符合習慣箭窜。
對于 Retrofit 2.0中新的URL定義方式,這里是我的建議:
-?Base URL: 總是以?/結尾
-?@Url:?不要以 / 開頭
比如
publicinterfaceAPIService{
@POST("user/list")
CallloadUsers();
}
publicvoiddoSomething(){
Retrofitretrofit=newRetrofit.Builder()
.baseUrl("http://api.nuuneoi.com/base/")
.addConverterFactory(GsonConverterFactory.create())
.build();
APIServiceservice=retrofit.create(APIService.class);
}
以上代碼中的loadUsers會從http://api.nuuneoi.com/base/user/list獲取數(shù)據(jù)衍腥。
而且在Retrofit 2.0中我們還可以在@Url里面定義完整的URL:
publicinterfaceAPIService{
@POST("http://api.nuuneoi.com/special/user/list")
CallloadSpecialUsers();
}
這種情況下Base URL會被忽略磺樱。
可以看到在URL的處理方式上發(fā)生了很大變化。它和前面的版本完全不同婆咸。如果你想把代碼遷移到Retrofit 2.0竹捉,別忘了修正URL部分的代碼。
現(xiàn)在需要OkHttp的支持
OkHttp 在Retrofit 1.9里是可選的尚骄。如果你想讓Retrofit 使用OkHttp 作為HTTP 連接接口块差,你需要手動包含okhttp?依賴。
但是在Retrofit 2.0中,OkHttp 是必須的憨闰,并且自動設置為了依賴状蜗。下面的代碼是從Retrofit 2.0的pom文件中抓取的。你不需要再做任何事情了鹉动。
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來攔截一個請求锉桑,但是它已經(jīng)從Retrofit 2.0 移除了排霉,因為HTTP連接層已經(jīng)轉為OkHttp。
結果就是,現(xiàn)在我們必須轉而使用OkHttp里面的Interceptor攻柠。首先你需要使用Interceptor創(chuàng)建一個OkHttpClient對象球订,如下:
OkHttpClientclient=newOkHttpClient();
client.interceptors().add(newInterceptor(){
@Override
publicResponseintercept(Chainchain)throwsIOException{
Responseresponse=chain.proceed(chain.request());
//?Do?anything?with?response?here
returnresponse;
}
});
然后傳遞創(chuàng)建的client到Retrofit的Builder鏈中。
Retrofitretrofit=newRetrofit.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團隊有已經(jīng)準備好了的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:
Retrofitretrofit=newRetrofit.Builder()
.baseUrl("http://api.nuuneoi.com/base/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
你的Service接口現(xiàn)在可以作為Observable返回了腾么!
Retrofitretrofit=newRetrofit.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(newSubscriber(){
@Override
publicvoidonCompleted(){
Toast.makeText(getApplicationContext(),
"Completed",
Toast.LENGTH_SHORT)
.show();
}
@Override
publicvoidonError(Throwablee){
Toast.makeText(getApplicationContext(),
e.getMessage(),
Toast.LENGTH_SHORT)
.show();
}
@Override
publicvoidonNext(DessertItemCollectionDaodessertItemCollectionDao){
Toast.makeText(getApplicationContext(),
dessertItemCollectionDao.getData().get(0).getName(),
Toast.LENGTH_SHORT)
.show();
}
});
完成!我相信RxJava的粉絲對這個變化相當滿意漆撞。
總結
還有許多其他變化饭寺,你可以在官方的Change Log中獲取更多詳情。不過叫挟,我相信我已經(jīng)在本文涵蓋了主要的issues艰匙。
你可能會好奇現(xiàn)在是否是切換到Retrofit 2.0 的時機?考慮到它仍然是beta階段抹恳,你可能會希望繼續(xù)停留在1.9除非你跟我一樣是一個喜歡嘗鮮的人员凝。?Retrofit 2.0用起來很好據(jù)我的經(jīng)驗來看還沒有發(fā)現(xiàn)bug。
注意Retrofit 1.9 的官方文檔現(xiàn)在已經(jīng)從Square的github主頁刪除奋献。我建議你現(xiàn)在就開始學習Retrofit 2.0健霹,盡快使用最新版本。