Retrofit簡(jiǎn)介
什么是Retrofit?
官方解釋?zhuān)?strong>一個(gè)為Java和Android提供的類(lèi)型安全的HTTP請(qǐng)求客戶(hù)端。
補(bǔ)充:Retrofit是 Square 公司開(kāi)發(fā)的一個(gè)用于網(wǎng)絡(luò)請(qǐng)求的開(kāi)源庫(kù),內(nèi)部封裝了OkHttp,簡(jiǎn)化了我們的網(wǎng)絡(luò)請(qǐng)求配置。
下面,附上官網(wǎng)鏈接方便各位查閱學(xué)習(xí)。
- 官網(wǎng)鏈接:http://square.github.io/retrofit/
- GitHub:https://github.com/square/retrofit
Retrofit使用實(shí)例
今天,Blogger用一個(gè)簡(jiǎn)單的實(shí)例來(lái)介紹下Retrofit的使用。
數(shù)據(jù)來(lái)源
使用的數(shù)據(jù)接口來(lái)自 GankIO(干貨集中營(yíng))
數(shù)據(jù)接口鏈接: http://gank.io/api/data/數(shù)據(jù)類(lèi)型/請(qǐng)求個(gè)數(shù)/第幾頁(yè)
- 數(shù)據(jù)類(lèi)型: 福利 | Android | iOS | 休息視頻 | 拓展資源 | 前端 | all
- 請(qǐng)求個(gè)數(shù): 數(shù)字,大于0
- 第幾頁(yè):數(shù)字,大于0
接下來(lái),我們想得到『福利』類(lèi)型的第1頁(yè)、前3條的數(shù)據(jù),鏈接補(bǔ)全如下:
http://gank.io/api/data/福利/3/1
在瀏覽器打開(kāi)鏈接后,我們可以看到數(shù)據(jù)的返回情況,如下圖所示(紅色文字是『截圖注釋』):

接下來(lái)我們要做的就是:在Android客戶(hù)端使用Retrofit請(qǐng)求數(shù)據(jù),之后用Log將數(shù)據(jù)打印出來(lái)(證明我們拿到數(shù)據(jù)了)。
Retrofit數(shù)據(jù)請(qǐng)求步驟
1. 添加Retrofit庫(kù)。
在應(yīng)用工程下的build.gradle文件中添加依賴(lài)庫(kù)。
dependencies {
......
// Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
// Retrofit - Gson數(shù)據(jù)轉(zhuǎn)換工具
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
}
2. 建立數(shù)據(jù)模型。
看到瀏覽器返回的數(shù)據(jù),我們可以將數(shù)據(jù)層次分為兩級(jí),最外層為第一級(jí),包含一個(gè)『數(shù)據(jù)反饋狀態(tài)』和一個(gè)『數(shù)據(jù)列表』,額外添加toString()方法方便Log打印。(第一級(jí)數(shù)據(jù)模型如下所示):
/**
* @ClassName: GankIOData
* @Description: GankIO - 數(shù)據(jù)模型
* @Author: wangnan7
* @Date: 2016/12/30 下午5:27
*/
public class GankIOData implements Serializable {
public boolean error; /* 數(shù)據(jù)是否出錯(cuò) */
public List<GankIOBaseData> results; /* 數(shù)據(jù)列表 */
@Override
public String toString() {
return "GankIOData{" +
"error=" + error +
", results=" + results +
'}';
}
}
第二級(jí)數(shù)據(jù)模型是每條數(shù)據(jù)的詳情信息,額外添加toString()方法方便Log打印,如下所示:
/**
* @ClassName: GankIOBaseData
* @Description: GankIO - 基本數(shù)據(jù)模型
* @Author: wangnan7
* @Date: 2016/12/30 下午5:29
*/
public class GankIOBaseData implements Serializable {
public String _id; /* 數(shù)據(jù)ID (例:"_id": "5865ad4e421aa94dbe2ccdb0")*/
public String createdAt; /* 創(chuàng)建時(shí)間 (例:"createdAt": "2016-12-30T08:41:50.830Z")*/
public String desc; /* 描述 (例:"desc": "12-30") */
public String publishedAt; /* 發(fā)布時(shí)間 (例:"publishedAt": "2016-12-30T16:16:11.125Z")*/
public String source; /* 來(lái)源 (例:"source": "chrome")*/
public String type; /* 類(lèi)型 (例:"type": "\u798f\u5229")*/
public String url; /* 圖片鏈接 (例:"url": "http://ww4.sinaimg.cn/large/610dc034jw1fb8iv9u08ij20u00u0tc7.jpg")*/
public boolean used; /* 是否被使用過(guò) (例:"used": true)*/
public String who; /* 數(shù)據(jù)提供者 (例:"who": "daimajia")*/
@Override
public String toString() {
return "GankIOBaseData{" +
"_id='" + _id + '\'' +
", createdAt='" + createdAt + '\'' +
", desc='" + desc + '\'' +
", publishedAt='" + publishedAt + '\'' +
", source='" + source + '\'' +
", type='" + type + '\'' +
", url='" + url + '\'' +
", used=" + used +
", who='" + who + '\'' +
'}';
}
}
3. 建立服務(wù)接口。
我們將之前的接口鏈接(http ://gank.io/api/data/數(shù)據(jù)類(lèi)型/請(qǐng)求個(gè)數(shù)/第幾頁(yè))拆分為兩部分:
- 第1部分:http://gank.io/ (主機(jī)地址部分)
- 第2部分:api/data/數(shù)據(jù)類(lèi)型/請(qǐng)求個(gè)數(shù)/第幾頁(yè) (路徑及參數(shù)部分)
接下來(lái),根據(jù)第2部分建立數(shù)據(jù)服務(wù)接口,代碼如下:
/**
* @ClassName: RetrofitService
* @Description: 干貨集中營(yíng) - 數(shù)據(jù)服務(wù)接口
* @Author: wangnan7
* @Date: 2016/12/30 下午5:40
*/
public interface RetrofitService {
/**
* 獲取GankIO數(shù)據(jù)(http://gank.io/api/data/數(shù)據(jù)類(lèi)型/請(qǐng)求個(gè)數(shù)/第幾頁(yè))
*
* @param type 數(shù)據(jù)類(lèi)型:福利 | Android | iOS | 休息視頻 | 拓展資源 | 前端 | all
* @param count 請(qǐng)求個(gè)數(shù):數(shù)字,大于0
* @param page 第幾頁(yè): 數(shù)字,大于0
*/
@GET("api/data/{type}/{count}/{page}")
Call<GankIOData> getGankIOData(@Path("type") String type, @Path("count") int count, @Path("page") int page);
}
@GET:當(dāng)前接口請(qǐng)求為Get請(qǐng)求。
@Path:路徑補(bǔ)全。例:@Path("type") String type ,我們傳入的type形參值會(huì)填入{type}中補(bǔ)全路徑。
4. 構(gòu)建Retrofit對(duì)象并請(qǐng)求接口數(shù)據(jù)。
在MainActivity中創(chuàng)建Retrofit對(duì)象并進(jìn)行接口數(shù)據(jù)請(qǐng)求,代碼如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Retrofit retrofit = new Retrofit.Builder() /* 創(chuàng)建一個(gè)Retrofit建造者 */
.baseUrl("http://gank.io/") /* 傳入請(qǐng)求接口的主機(jī)地址 */
.addConverterFactory(GsonConverterFactory.create()) /* 添加Gson數(shù)據(jù)轉(zhuǎn)換 */
.build(); /* 建立Retrofit對(duì)象 */
/* 創(chuàng)建服務(wù)接口實(shí)現(xiàn)類(lèi) */
RetrofitService service = retrofit.create(RetrofitService.class);
/* 補(bǔ)全接口請(qǐng)求參數(shù),得到Call對(duì)象,執(zhí)行完此步Retrofit的作用就已經(jīng)完成了。(Call是Okhttp中的一個(gè)概念,代表了一個(gè)實(shí)際的HTTP請(qǐng)求) */
Call<GankIOData> call = service.getGankIOData("福利", 3, 1);
/* 請(qǐng)求網(wǎng)絡(luò),異步獲取數(shù)據(jù) */
call.enqueue(new Callback<GankIOData>() {
@Override
public void onResponse(Call<GankIOData> call, Response<GankIOData> response) {
if(response.isSuccessful()){ /* 檢查返回的網(wǎng)絡(luò)狀態(tài)碼是否在[200..300),一般200最為常見(jiàn),300+表示請(qǐng)求的url被重定向了... */
GankIOData data = response.body(); /* 獲取數(shù)據(jù)模型 */
Log.e("TAG", data.toString()); /* 打印數(shù)據(jù) */
}
}
@Override
public void onFailure(Call<GankIOData> call, Throwable t) {
}
});
}
}
5. 添加聯(lián)網(wǎng)權(quán)限。
不要忘記在AndroidManifest文件中添加聯(lián)網(wǎng)權(quán)限手累,就不打三遍了O(∩_∩)O
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testing.retrofitdemo">
<!-- 聯(lián)網(wǎng)權(quán)限 -->
<uses-permission android:name="android.permission.INTERNET"/>
......
</manifest>
最后運(yùn)行下程序,我們的Log工具就將數(shù)據(jù)打印出來(lái)了。
12-30 17:48:57.394 6915-6915/com.example.testing.retrofitdemo E/TAG: GankIOData{error=false, results=[GankIOBaseData{_id='5865ad4e421aa94dbe2ccdb0', createdAt='2016-12-30T08:41:50.830Z', desc='12-30', publishedAt='2016-12-30T16:16:11.125Z', source='chrome', type='福利', url='http://ww4.sinaimg.cn/large/610dc034jw1fb8iv9u08ij20u00u0tc7.jpg', used=true, who='daimajia'}, GankIOBaseData{_id='58645be0421aa94dbbd82bac', createdAt='2016-12-29T08:42:08.389Z', desc='12-29', publishedAt='2016-12-29T11:56:56.946Z', source='chrome', type='福利', url='http://ww4.sinaimg.cn/large/610dc034gw1fb7d9am05gj20u011hq64.jpg', used=true, who='daimajia'}, GankIOBaseData{_id='58632374421aa9723d29b9ba', createdAt='2016-12-28T10:29:08.507Z', desc='12-28', publishedAt='2016-12-28T11:57:39.616Z', source='chrome', type='福利', url='http://ww1.sinaimg.cn/large/610dc034gw1fb6aqccs3nj20u00u0wk4.jpg', used=true, who='daimajia'}]}
至此,我們的數(shù)據(jù)就請(qǐng)求成功了。
Retrofit混淆配置
我們一般在給應(yīng)用打包上線(xiàn)時(shí)會(huì)給代碼添加混淆配置,一來(lái)是為了防止別人反編譯,二來(lái)是可以給apk文件瘦身。
混淆開(kāi)啟方法,在應(yīng)用工程下的build.gradle文件中,找到minifyEnabled配置項(xiàng)并設(shè)置為true,如下所示(注意這里是release配置,debug運(yùn)行時(shí)混淆開(kāi)關(guān)還是關(guān)著的):
android {
......
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
對(duì)于Retrofit,開(kāi)啟混淆開(kāi)關(guān)后,我們還要在混淆文件(proguard-rules.pro)中添加一些混淆配置,在Retrofit官網(wǎng)中也有混淆的相關(guān)配置說(shuō)明,如下所示:
如果你要在你的工程中使用混淆,需要添加以下幾行配置項(xiàng):
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
雖然官網(wǎng)給出了混淆配置,但還是想吐槽兩句...
官網(wǎng)給的混淆配置其實(shí)并不完全,我們都知道Retrofit是對(duì)Okhttp的封裝,Okhttp不需要添加混淆配置嗎?另外,我們使用了Gson轉(zhuǎn)換,Gson不需要添加混淆配置嗎?還有,如果我們bean目錄的數(shù)據(jù)模型的字段被混淆了,還能和服務(wù)端返回的數(shù)據(jù)對(duì)上嗎?
- 第一點(diǎn):如果不添加Okhttp的混淆配置,編譯到okio時(shí)會(huì)報(bào)錯(cuò)。
- 第二點(diǎn):此處Gson可以不添加混淆配置(這意味著Gson將會(huì)是混淆的)。
- 第三點(diǎn):要保證我們的數(shù)據(jù)模型不被混淆,否則得到的數(shù)據(jù)全是null。
最后,給各位列一下我的混淆文件中的相關(guān)配置:
# Retrofit
-dontnote retrofit2.Platform
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
-dontwarn retrofit2.Platform$Java8
-keepattributes Signature
-keepattributes Exceptions
# okhttp
-dontwarn okio.**
# Gson
-keep class com.example.testing.retrofitdemo.bean.**{*;} # 自定義數(shù)據(jù)模型的bean目錄
配置之后,打包混淆后的release版應(yīng)用就能拿到數(shù)據(jù)了。
Retrofit進(jìn)階推薦
最后,給想要繼續(xù)進(jìn)階Retrofit的小伙伴們推薦一篇博客: