引言
Android項(xiàng)目必備基本輪子--------
異步網(wǎng)絡(luò)請(qǐng)求框架周蹭。
先不考慮在手項(xiàng)目的進(jìn)度趋艘,也不管UI組件的深探,先來(lái)將Restful客戶(hù)端的輪子造起來(lái)凶朗!
現(xiàn)在A(yíng)ndroid 市面上很火的當(dāng)然是 Retrofit
+RxJava
+ OkHttp
, 功能強(qiáng)大瓷胧,簡(jiǎn)單易用,因此選用這套方案來(lái)改造網(wǎng)絡(luò)庫(kù)棚愤。
簡(jiǎn)介:
Retrofit: Retrofit
是Square公司開(kāi)發(fā)的一款針對(duì)Android 網(wǎng)絡(luò)請(qǐng)求的框架搓萧。底層基于OkHttp
實(shí)現(xiàn),OkHttp 已經(jīng)得到了Google 官方的認(rèn)可宛畦。Retrofit官網(wǎng)
OkHttp: 也是Square 開(kāi)源的網(wǎng)絡(luò)請(qǐng)求庫(kù)
RxJava:RxJava
在 GitHub 主頁(yè)上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個(gè)在 Java VM 上使用可觀(guān)測(cè)的序列來(lái)組成異步的矛绘、基于事件的程序的庫(kù))。這就是 RxJava 刃永,概括得非常精準(zhǔn)货矮。總之就是讓異步操作變得非常簡(jiǎn)單斯够。
各自的職責(zé):Retrofit
負(fù)責(zé)請(qǐng)求的數(shù)據(jù)和請(qǐng)求的結(jié)果囚玫,使用接口的方式呈現(xiàn),OkHttp
負(fù)責(zé)請(qǐng)求的過(guò)程读规,RxJava
負(fù)責(zé)異步抓督,各種線(xiàn)程之間的切換。
RxJava
+ Retrofit
+ okHttp
已成為當(dāng)前Android 網(wǎng)絡(luò)請(qǐng)求最流行的方式束亏。
分別實(shí)例介紹
一铃在,Retrofit 寫(xiě)一個(gè)網(wǎng)絡(luò)請(qǐng)求
以獲取豆瓣 Top250 榜單為例,地址:https://api.douban.com/v2/movie/
- 首先,要使用
Retrofit
,你肯定需要把它的包引入定铜,在你的build.gradle
文件中添加如下配置:
//下面兩個(gè)是RxJava 和RxAndroid
compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:1.2.0'
compile 'com.squareup.retrofit2:retrofit:2.4.0'//retrofit
compile 'com.squareup.retrofit2:converter-gson:2.4.0'//轉(zhuǎn)換器阳液,請(qǐng)求結(jié)果轉(zhuǎn)換成Model
compile 'com.squareup.retrofit2:adapter-rxjava:2.4.0'//配合Rxjava 使用
- 創(chuàng)建一個(gè)
Retrofit
實(shí)例,并且完成相關(guān)的配置
public static final String BASE_URL = "https://api.douban.com/v2/movie/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
說(shuō)明:配置了接口的baseUrl和一個(gè)converter,GsonConverterFactory 是默認(rèn)提供的Gson 轉(zhuǎn)換器揣炕,Retrofit 也支持其他的一些轉(zhuǎn)換器帘皿,詳情請(qǐng)看官網(wǎng)Retrofit官網(wǎng)
- 創(chuàng)建一個(gè)接口 ,代碼如下:
public interface MovieService {
//獲取豆瓣Top250 榜單
@GET("top250")
Call<MovieSubject> getTop250(@Query("start") int start,@Query("count")int count);
}
- 用Retrofit 創(chuàng)建 接口實(shí)例 MoiveService,并且調(diào)用接口中的方法進(jìn)行網(wǎng)絡(luò)請(qǐng)求畸陡,代碼如下:
//獲取接口實(shí)例
MovieService MovieService movieService = retrofit.create(MovieService.class);
//調(diào)用方法得到一個(gè)Call
Call<MovieSubject> call = movieService.getTop250(0,20);
//進(jìn)行網(wǎng)絡(luò)請(qǐng)求
call.enqueue(new Callback<MovieSubject>() {
@Override
public void onResponse(Call<MovieSubject> call, Response<MovieSubject> response) {
mMovieAdapter.setMovies(response.body().subjects);
mMovieAdapter.notifyDataSetChanged();
}
@Override
public void onFailure(Call<MovieSubject> call, Throwable t) {
t.printStackTrace();
}
});
以上是異步方式請(qǐng)求鹰溜,還有同步方式execute()
,返回一個(gè)Response,代碼如下:
Response<MovieSubject> response = call.execute();
以上就是用Retrofit 完成了一個(gè)網(wǎng)絡(luò)請(qǐng)求,獲取豆瓣top250 榜單電影丁恭,效果圖如下:
以上示例是用get
方式完成曹动,如果要使用post
方式,我們只需要修改一下接口中的方法定義牲览,如下:
public interface MovieService {
//獲取豆瓣Top250 榜單
@FormUrlEncoded
@POST("top250")
Call<MovieSubject> getTop250(@Field("start") int start, @Field("count") int count);
}
說(shuō)明:使用
POST
請(qǐng)求方式時(shí)仁期,只需要更改方法定義的標(biāo)簽,用@POST
標(biāo)簽竭恬,參數(shù)標(biāo)簽用@Field
或者@Body
或者FieldMap
跛蛋,注意:使用POST 方式時(shí)注意2點(diǎn),1痊硕,必須加上 @FormUrlEncoded標(biāo)簽赊级,否則會(huì)拋異常。2岔绸,使用POST方式時(shí)理逊,必須要有參數(shù),否則會(huì)拋異常, 源碼拋異常的地方如下:
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
以上就是一個(gè)使用Retrofit 完成一個(gè)網(wǎng)絡(luò)請(qǐng)求的完整示例盒揉,其他標(biāo)簽使用方式請(qǐng)看官網(wǎng)Retrofit官網(wǎng)晋被,官網(wǎng)用法也介紹的比較詳細(xì),此外刚盈,發(fā)現(xiàn)了一篇博客也介紹得比較詳細(xì)羡洛,Retrofit用法詳解
二,配合RxJava 使用
- 更改定義的接口藕漱,返回值不再是一個(gè)Call ,而是返回的一個(gè)Observble.
public interface MovieService {
//獲取豆瓣Top250 榜單
@GET("top250")
Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
}
- 創(chuàng)建Retrofit 的時(shí)候添加如下代碼
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- 添加轉(zhuǎn)換器Converter(將json 轉(zhuǎn)為JavaBean)
addConverterFactory(GsonConverterFactory.create())
- Activity 或者 Fragment 中傳入 Subscriber 建立訂閱關(guān)系
Subscription subscription = movieService.getTop250(0,20)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<MovieSubject>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(MovieSubject movieSubject) {
mMovieAdapter.setMovies(movieSubject.subjects);
mMovieAdapter.notifyDataSetChanged();
}
});
以上是加入RxJava
后的網(wǎng)絡(luò)請(qǐng)求欲侮,返回不再是一個(gè)Call
,而是一個(gè)Observable
, 在Activity
/ Fragment
中傳入一個(gè)Subscriber 建立訂閱關(guān)系,就可以在 onNext 中處理結(jié)果了肋联,RxJava 的好處是幫我處理線(xiàn)程之間的切換威蕉,我們可以在指定訂閱的在哪個(gè)線(xiàn)程,觀(guān)察在哪個(gè)線(xiàn)程橄仍。我們可以通過(guò)操作符進(jìn)行數(shù)據(jù)變換韧涨。整個(gè)過(guò)程都是鏈?zhǔn)降碾蛊荩?jiǎn)化邏輯。其中FlatMap 操作符 還可以解除多層嵌套的問(wèn)題虑粥∪缧ⅲ總之,RxJava 很強(qiáng)大舀奶,能幫我處理很多復(fù)雜的場(chǎng)景暑竟,如果熟練使用的話(huà)斋射,那么能提升我們的開(kāi)發(fā)效率育勺。這里不打算講RxJava 的內(nèi)容,如果還不了解RxJava ,或者還對(duì)RxJava不熟悉的話(huà)罗岖,推薦幾篇寫(xiě)很優(yōu)秀的博客涧至。
1,RxJava 的經(jīng)典文章,扔物線(xiàn)的 給 Android 開(kāi)發(fā)者的 RxJava 詳解
2桑包,關(guān)于RxJava 友好的文章
3南蓬,關(guān)于RxJava 友好的文章-進(jìn)階
三,加入 OkHttp 配置
通過(guò)OkHttpClient
可以配置很多東西哑了,比如鏈接超時(shí)時(shí)間
赘方,緩存
,攔截器
等等弱左。代碼如下:
// 創(chuàng)建 OKHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//連接超時(shí)時(shí)間
builder.writeTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//寫(xiě)操作 超時(shí)時(shí)間
builder.readTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//讀操作超時(shí)時(shí)間
// 添加公共參數(shù)攔截器
BasicParamsInterceptor basicParamsInterceptor = new BasicParamsInterceptor.Builder()
.addHeaderParam("userName","")//添加公共參數(shù)
.addHeaderParam("device","")
.build();
builder.addInterceptor(basicParamsInterceptor);
// 創(chuàng)建Retrofit
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConfig.BASE_URL)
.build();
以上只是配置了一些簡(jiǎn)單的項(xiàng)窄陡,如,連接超時(shí)時(shí)間
拆火,實(shí)際項(xiàng)目中跳夭,我們可能有一些公共的參數(shù),如 :設(shè)備信息
们镜,渠道
币叹,Token
之類(lèi)的,每個(gè)接口都需要用模狭,我們可以寫(xiě)一個(gè)攔截器颈抚,然后配置到OKHttpClient
里,通過(guò) builder.addInterceptor(basicParamsInterceptor) 添加嚼鹉,這樣我們就不用每個(gè)接口都添加這些參數(shù)了邪意。緩存也可以通過(guò)寫(xiě)一個(gè)攔截器來(lái)實(shí)現(xiàn)(后面文章再講)。
以上就是Retrofit+RxJava+OkHttp實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的簡(jiǎn)單演示反砌,如果每個(gè)接口都這么寫(xiě)的話(huà)雾鬼,代碼量太多,而且不優(yōu)雅宴树。所以還需要我們封裝一下策菜,接下來(lái)講一下對(duì)網(wǎng)絡(luò)請(qǐng)求框架的封裝。
參考博客:
1,Retrofit用法詳解
2又憨,基于Retrofit翠霍、OkHttp、Gson封裝通用網(wǎng)絡(luò)框架
3, RxJava 與 Retrofit 結(jié)合的最佳實(shí)踐
封裝
一蠢莺,創(chuàng)建一個(gè)統(tǒng)一生成接口實(shí)例的管理類(lèi)RetrofitServiceManager
我們知道寒匙,每一個(gè)請(qǐng)求,都需要一個(gè)接口躏将,里面定義了請(qǐng)求方法和請(qǐng)求參數(shù)等等锄弱,而獲取接口實(shí)例需要通過(guò)一個(gè)Retrofit實(shí)例,這一步都是相同的,因此祸憋,我們可以把這些相同的部分抽取出來(lái)会宪,代碼如下:
/*
*
*/
public class RetrofitServiceManager {
private static final int DEFAULT_TIME_OUT = 5;//超時(shí)時(shí)間 5s
private static final int DEFAULT_READ_TIME_OUT = 10;
private Retrofit mRetrofit;
private RetrofitServiceManager(){
// 創(chuàng)建 OKHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//連接超時(shí)時(shí)間
builder.writeTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS);//寫(xiě)操作 超時(shí)時(shí)間
builder.readTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS);//讀操作超時(shí)時(shí)間
// 添加公共參數(shù)攔截器
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
.addHeaderParams("paltform","android")
.addHeaderParams("userToken","1234343434dfdfd3434")
.addHeaderParams("userId","123445")
.build();
builder.addInterceptor(commonInterceptor);
// 創(chuàng)建Retrofit
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConfig.BASE_URL)
.build();
}
private static class SingletonHolder{
private static final RetrofitServiceManager INSTANCE = new RetrofitServiceManager();
}
/**
* 獲取RetrofitServiceManager
* @return
*/
public static RetrofitServiceManager getInstance(){
return SingletonHolder.INSTANCE;
}
/**
* 獲取對(duì)應(yīng)的Service
* @param service Service 的 class
* @param <T>
* @return
*/
public <T> T create(Class<T> service){
return mRetrofit.create(service);
}
}
說(shuō)明:創(chuàng)建了一個(gè)RetrofitServiceManager類(lèi),該類(lèi)采用單例模式蚯窥,在私有的構(gòu)造方法中掸鹅,生成了Retrofit 實(shí)例,并配置了OkHttpClient和一些公共配置拦赠。提供了一個(gè)create()方法巍沙,生成接口實(shí)例,接收Class范型荷鼠,因此項(xiàng)目中所有的接口實(shí)例Service都可以用這個(gè)來(lái)生成句携,代碼如下:
mMovieService = RetrofitServiceManager.getInstance().create(MovieService.class);
通過(guò)create()方法生成了一個(gè)MovieService
二,創(chuàng)建接口颊咬,通過(guò)第一步獲取實(shí)例
上面已經(jīng)有了可以獲取接口實(shí)例的方法因此我們需要?jiǎng)?chuàng)建一個(gè)接口务甥,代碼如下:
public interface MovieService{
//獲取豆瓣Top250 榜單
@GET("top250")
Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
@FormUrlEncoded
@POST("/x3/weather")
Call<String> getWeather(@Field("cityId") String cityId, @Field("key") String key);
}
好了,有了接口我們就可以獲取到接口實(shí)例了mMovieService
三喳篇,創(chuàng)建一個(gè)業(yè)務(wù)Loader 敞临,如XXXLoder,獲取Observable并處理相關(guān)業(yè)務(wù)
解釋一下為什么會(huì)出現(xiàn)Loader ,我看其他相關(guān)文章說(shuō)麸澜,每一個(gè)Api 都寫(xiě)一個(gè)接口挺尿,我覺(jué)得這樣很麻煩,因此就把請(qǐng)求邏輯封裝在在一個(gè)業(yè)務(wù)Loader 里面炊邦,一個(gè)Loader里面可以處理多個(gè)Api 接口编矾。代碼如下:
public class MovieLoader extends ObjectLoader {
private MovieService mMovieService;
public MovieLoader(){
mMovieService = RetrofitServiceManager.getInstance().create(MovieService.class);
}
/**
* 獲取電影列表
* @param start
* @param count
* @return
*/
public Observable<List<Movie>> getMovie(int start, int count){
return observe(mMovieService.getTop250(start,count))
.map(new Func1<MovieSubject, List<Movie>>() {
@Override
public List<Movie> call(MovieSubject movieSubject) {
return movieSubject.subjects;
}
});
}
public Observable<String> getWeatherList(String cityId,String key){
return observe(mMovieService.getWeather(cityId,key))
.map(new Func1<String, String>() {
@Override
public String call(String s) {
//可以處理對(duì)應(yīng)的邏輯后在返回
return s;
}
});
}
public interface MovieService{
//獲取豆瓣Top250 榜單
@GET("top250")
Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
@FormUrlEncoded
@POST("/x3/weather")
Call<String> getWeather(@Field("cityId") String cityId, @Field("key") String key);
}
}
創(chuàng)建一個(gè)MovieLoader,構(gòu)造方法中生成了mMovieService,而Service 中可以定義和業(yè)務(wù)相關(guān)的多個(gè)api,比如:例子中的MovieService中,可以定義和電影相關(guān)的多個(gè)api,獲取電影列表馁害、獲取電影詳情、搜索電影等api碘菜,就不用定義多個(gè)接口了凹蜈。
上面的代碼中限寞,MovieLoader是從ObjectLoader 中繼承下來(lái)的,ObjectLoader 提取了一些公共的操作仰坦。代碼如下:
/**
*
* 將一些重復(fù)的操作提出來(lái)履植,放到父類(lèi)以免Loader 里每個(gè)接口都有重復(fù)代碼
* Created by zhouwei on 16/11/10.
*
*/
public class ObjectLoader {
/**
*
* @param observable
* @param <T>
* @return
*/
protected <T> Observable<T> observe(Observable<T> observable){
return observable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
相當(dāng)于一個(gè)公共方法,其實(shí)也可以放在一個(gè)工具類(lèi)里面悄晃,后面做緩存的時(shí)候會(huì)用到這個(gè)父類(lèi)玫霎,所以就把這個(gè)方法放到父類(lèi)里面。
四妈橄,Activity/Fragment 中的調(diào)用
創(chuàng)建Loader實(shí)例
mMovieLoader = new MovieLoader();
通過(guò)Loader 調(diào)用方法獲取結(jié)果,代碼如下:
/*
*
* 獲取電影列表
*/
private void getMovieList(){
mMovieLoader.getMovie(0,10).subscribe(new Action1<List<Movie>>() {
@Override
public void call(List<Movie> movies) {
mMovieAdapter.setMovies(movies);
mMovieAdapter.notifyDataSetChanged();
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.e("TAG","error message:"+throwable.getMessage());
}
});
}
以上就完成請(qǐng)求過(guò)程的封裝庶近,現(xiàn)在添加一個(gè)新的請(qǐng)求,只需要添加一個(gè)業(yè)務(wù)Loader 類(lèi)眷细,然后通過(guò)Loader調(diào)用方法獲取結(jié)果就行了拦盹,是不是方便了很多鹃祖?但是在實(shí)際項(xiàng)目中這樣是不夠的溪椎,還能做進(jìn)一步簡(jiǎn)化。
五恬口,統(tǒng)一處理結(jié)果和錯(cuò)誤
1,統(tǒng)一處理請(qǐng)求結(jié)果
現(xiàn)實(shí)項(xiàng)目中校读,所有接口的返回結(jié)果都是同一格式,如:
{
"status": 200,
"message": "成功",
"data": {}
}
我們?cè)谡?qǐng)求api 接口的時(shí)候祖能,只關(guān)心我們想要的數(shù)據(jù)歉秫,也就上面的data,其他的東西我們不太關(guān)心,請(qǐng)求失敗的時(shí)候可以根據(jù)status判斷進(jìn)行錯(cuò)誤處理养铸,所以我們需要包裝一下雁芙。首先需要根據(jù)服務(wù)端定義的JSON 結(jié)構(gòu)創(chuàng)建一個(gè)BaseResponse 類(lèi),代碼如下:
/*
*
*
* 網(wǎng)絡(luò)請(qǐng)求結(jié)果 基類(lèi)
* Created by zhouwei on 16/11/10.
*/
public class BaseResponse<T> {
public int status;
public String message;
public T data;
public boolean isSuccess(){
return status == 200;
}
}
有了統(tǒng)一的格式數(shù)據(jù)后钞螟,我們需要?jiǎng)冸x出data 返回給上層調(diào)用者兔甘,創(chuàng)建一個(gè)PayLoad 類(lèi),代碼如下:
/*
* 剝離 最終數(shù)據(jù)
*/
public class PayLoad<T> implements Func1<BaseResponse<T>,T>{
@Override
public T call(BaseResponse<T> tBaseResponse) {
//獲取數(shù)據(jù)失敗時(shí)鳞滨,包裝一個(gè)Fault 拋給上層處理錯(cuò)誤
if(!tBaseResponse.isSuccess()){
throw new Fault(tBaseResponse.status,tBaseResponse.message);
}
return tBaseResponse.data;
}
}
PayLoad 繼承自Func1
,接收一個(gè)BaseResponse<T> , 就是接口返回的JSON數(shù)據(jù)結(jié)構(gòu)洞焙,返回的是T,就是data,判斷是否請(qǐng)求成功,請(qǐng)求成功返回Data,請(qǐng)求失敗包裝成一個(gè)Fault 返回給上層統(tǒng)一處理錯(cuò)誤拯啦。在Loader類(lèi)里面獲取結(jié)果后澡匪,通過(guò)map 操作符剝離數(shù)據(jù)。代碼如下:
public Observable<List<Movie>> getMovie(int start, int count){
return observe(mMovieService.getTop250(start,count))
.map(new PayLoad<List<Movie>>());
}
2褒链,統(tǒng)一處理錯(cuò)誤
在PayLoad 類(lèi)里面唁情,請(qǐng)求失敗時(shí),拋出了一個(gè)Fault 異常給上層甫匹,我在A(yíng)ctivity/Fragment 中拿到這個(gè)異常甸鸟,然后判斷錯(cuò)誤碼夯巷,進(jìn)行異常處理。在onError () 中添加代碼如下:
public void call(Throwable throwable) {
Log.e("TAG","error message:"+throwable.getMessage());
if(throwable instanceof Fault){
Fault fault = (Fault) throwable;
if(fault.getErrorCode() == 404){
//錯(cuò)誤處理
}else if(fault.getErrorCode() == 500){
//錯(cuò)誤處理
}else if(fault.getErrorCode() == 501){
//錯(cuò)誤處理
}
}
}
以上就可以對(duì)應(yīng)錯(cuò)誤碼處理相應(yīng)的錯(cuò)誤了哀墓。
六趁餐,添加公共參數(shù)
在實(shí)際項(xiàng)目中,每個(gè)接口都有一些基本的相同的參數(shù)篮绰,我們稱(chēng)之為公共參數(shù)
后雷,比如:userId
、userToken
吠各、userName
,deviceId
等等臀突,我們不必要,每個(gè)接口都去寫(xiě)贾漏,這樣就太麻煩了候学,因此我們可以寫(xiě)一個(gè)攔截器,在攔截器里面攔截請(qǐng)求纵散,為每個(gè)請(qǐng)求都添加相同的公共參數(shù)梳码。攔截器代碼如下:
/*
* 攔截器
* 向請(qǐng)求頭里添加公共參數(shù)
*/
public class HttpCommonInterceptor implements Interceptor {
private Map<String,String> mHeaderParamsMap = new HashMap<>();
public HttpCommonInterceptor() {}
@Override
public Response intercept(Chain chain) throws IOException {
Log.d("HttpCommonInterceptor","add common params");
Request oldRequest = chain.request();
// 添加新的參數(shù),添加到url 中
/* HttpUrl.Builder authorizedUrlBuilder = oldRequest.url().newBuilder()
.scheme(oldRequest.url().scheme())
.host(oldRequest.url().host());*/
// 新的請(qǐng)求
Request.Builder requestBuilder = oldRequest.newBuilder();
requestBuilder.method(oldRequest.method(), oldRequest.body());
//添加公共參數(shù),添加到header中
if(mHeaderParamsMap.size() > 0){
for(Map.Entry<String,String> params:mHeaderParamsMap.entrySet()){
requestBuilder.header(params.getKey(),params.getValue());
}
}
Request newRequest = requestBuilder.build();
return chain.proceed(newRequest);
}
public static class Builder{
HttpCommonInterceptor mHttpCommonInterceptor;
public Builder(){
mHttpCommonInterceptor = new HttpCommonInterceptor();
}
public Builder addHeaderParams(String key, String value){
mHttpCommonInterceptor.mHeaderParamsMap.put(key,value);
return this;
}
public Builder addHeaderParams(String key, int value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, float value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, long value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, double value){
return addHeaderParams(key, String.valueOf(value));
}
public HttpCommonInterceptor build(){
return mHttpCommonInterceptor;
}
}
}
以上就是添加公共參數(shù)的攔截器伍掀,在RetrofitServiceManager 類(lèi)里面加入OkHttpClient 配置就好了掰茶。代碼如下:
// 添加公共參數(shù)攔截器
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
.addHeaderParams("paltform","android")
.addHeaderParams("userToken","1234343434dfdfd3434")
.addHeaderParams("userId","123445")
.build();
builder.addInterceptor(commonInterceptor);
這樣每個(gè)請(qǐng)求都添加了公共參數(shù)。
封裝的類(lèi)放在http包下:
電影列表:(數(shù)據(jù)來(lái)自豆瓣)