詳解Retrofit2.0 公共參數(shù)(固定參數(shù))
本文主要介紹了Retrofit2.0 公共參數(shù)(固定參數(shù)),分享給大家,具體如下:
請先閱讀:
Retrofit 動態(tài)參數(shù)(非固定參數(shù)、非必須參數(shù))(Get、Post請求)
在實(shí)際項(xiàng)目中,對于有需要統(tǒng)一進(jìn)行公共參數(shù)添加的網(wǎng)絡(luò)請求,可以使用下面的代碼來實(shí)現(xiàn):
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(ctx).setRequestInterceptor(new RequestInterceptor() {
@Override
public void intercept(RequestFacade request) {
request.addQueryParam("publicParams", "1");
}
}).setConverter(new BaseConverter())
.build();
在RestAdapter的實(shí)例化對象的時候,為其指定一個RequestInterceptor接口的實(shí)現(xiàn)類即可,在該類中,可以對請求體的相關(guān)參數(shù)進(jìn)行設(shè)置,如addHeader、addQueryParam等。
不過遺憾的是Retrofit2.0已經(jīng)沒有了該類,該怎么做呢?通過Interceptor實(shí)現(xiàn)。
Interceptor是攔截器, 在發(fā)送之前, 添加一些參數(shù), 或者獲取一些信息。
/**
* 封裝公共參數(shù)(Key和密碼)
* <p>
*/
public class CommonInterceptor implements Interceptor {
private final String mApiKey;
private final String mApiSecret;
public CommonInterceptor(String apiKey, String apiSecret) {
mApiKey = apiKey;
mApiSecret = apiSecret;
}
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
String marvelHash = ApiUtils.generateMarvelHash(mApiKey, mApiSecret);
Request oldRequest = chain.request();
// 添加新的參數(shù)
HttpUrl.Builder authorizedUrlBuilder = oldRequest.url()
.newBuilder()
.scheme(oldRequest.url().scheme())
.host(oldRequest.url().host())
.addQueryParameter(MarvelService.PARAM_API_KEY, mApiKey)
.addQueryParameter(MarvelService.PARAM_TIMESTAMP, ApiUtils.getUnixTimeStamp())
.addQueryParameter(MarvelService.PARAM_HASH, marvelHash);
// 新的請求
Request newRequest = oldRequest.newBuilder()
.method(oldRequest.method(), oldRequest.body())
.url(authorizedUrlBuilder.build())
.build();
return chain.proceed(newRequest);
}
}
Okhttp3使用了裝飾者模式, 使用Builder添加Interceptor。
CommonInterceptor commonInterceptor = new CommonInterceptor(
"key", "Secret");
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(commonInterceptor)
.build();
// 適配器
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("url")
.addConverterFactory(GsonConverterFactory.create()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(client)
.build();
有時候你找到了一條線,就能順著線找到更多。
背景
在 Android Http API 請求開發(fā)中經(jīng)常遇到這樣的需求:每一次請求帶上一個或者多個固定不變的參數(shù),例如:
- 設(shè)備唯一標(biāo)識:device_id = 7a4391e28f309c21
- 業(yè)務(wù)唯一標(biāo)識:uid = 2231001
- 平臺類型:platform = android
- 客戶端版本號:version_code = 6
- …
這些參數(shù)是每一次發(fā)生請求都需要的,我們姑且稱他們?yōu)楣矃?shù)(或者基礎(chǔ)參數(shù))。公共參數(shù)一般以 header line、url query 或者 post body(較少) 這些形式插入請求。
實(shí)現(xiàn)
如果使用 OkHttp 作為 http request client, 這件事情就變得簡單多了。OkHttp 提供了強(qiáng)大的攔截器組件 (Interceptor):
Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.
也就是說,OkHttp 的攔截器功能之一就是對將要發(fā)出的請求進(jìn)行攔截、改造然后再發(fā)出。這正是我們想要的。BasicParamsInterceptor 實(shí)現(xiàn)了 okhttp3.Interceptor 接口。
實(shí)現(xiàn) public Response intercept(Chain chain) throws IOException 方法。使用 Builder 模式,暴露以下接口:
addParam(String key, String value)
post 請求,且 body type 為 x-www-form-urlencoded 時,鍵值對公共參數(shù)插入到 body 參數(shù)中,其他情況插入到 url query 參數(shù)中。
addParamsMap(Map paramsMap)
同上,不過這里用鍵值對 Map 作為參數(shù)批量插入。
addHeaderParam(String key, String value)
在 header 中插入鍵值對參數(shù)。
addHeaderParamsMap(Map headerParamsMap)
在 header 中插入鍵值對 Map 集合,批量插入。
addHeaderLine(String headerLine)
在 header 中插入 headerLine 字符串,字符串需要符合 -1 != headerLine.indexOf(“:”) 的規(guī)則,即可以解析成鍵值對。
addHeaderLinesList(List headerLinesList)
同上,headerLineList: List 為參數(shù),批量插入 headerLine。
addQueryParam(String key, String value)
插入鍵值對參數(shù)到 url query 中。
addQueryParamsMap(Map queryParamsMap)
插入鍵值對參數(shù) map 到 url query 中,批量插入。
示例
使用 Buider 模式創(chuàng)建 Interceptor 對象,然后調(diào)用 OkHttp 的 addInterceptor(Interceptor i) 方法將 interceptor 對象添加至 client 中:
BasicParamsInterceptor basicParamsInterceptor =
new OkPublicParamsInterceptor.Builder()
.addHeaderParam("device_id", DeviceUtils.getDeviceId())
.addParam("uid", UserModel.getInstance().getUid())
.addQueryParam("api_version", "1.1")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(basicParamsInterceptor)
.build();
TODO
- 自動時間戳公共參數(shù)的支持
- 動態(tài)參數(shù)的支持(例如登錄后插入服務(wù)器返回的 uid)
源碼
源碼與引用:https://github.com/jkyeo/okhttp-basicparamsinterceptor
basicparamsinterceptor應(yīng)用
配置基本提交參數(shù)
我們可以建一個攔截器,這里我舉例加些簡單的系統(tǒng)參數(shù),如下:
class HttpBaseParamsLoggingInterceptor implements Interceptor{
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
RequestBody formBody = new FormBody.Builder()
.add("userId", "10000")
.add("sessionToken", "E34343RDFDRGRT43RFERGFRE")
.add("q_version", "1.1")
.add("device_id", "android-344365")
.add("device_os", "android")
.add("device_osversion","6.0")
.add("req_timestamp", System.currentTimeMillis() + "")
.add("app_name","forums")
.add("sign", "md5")
.build();
String postBodyString = Utils.bodyToString(request.body());
postBodyString += ((postBodyString.length() > 0) ? "&" : "") + Utils.bodyToString(formBody);
request = requestBuilder
.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"),
postBodyString))
.build();
return chain.proceed(request);
}
}
上面Utils類是使用的okio.Buffer里面的工具類。通過RequestBody構(gòu)建要上傳的一些基本公共的參數(shù),然后通過”&”符號在http 的body里面其他要提交參數(shù)拼接。然后再通過requestBuilder重新創(chuàng)建request對象,然后再通過chain.proceed(request)返回Response 。
接下來在創(chuàng)建OkHttpClient對象的時候修改為如下代碼:
mOkHttpClient = new OkHttpClient.Builder() .addInterceptor(interceptor) .addInterceptor(new HttpBaseParamsLoggingInterceptor()) .build();
這樣就添加好了一些基本的公共參數(shù)。
下面我們借助BasicParamsInterceptor實(shí)現(xiàn),代碼如下:
public class BasicParamsInterceptor implements Interceptor {
Map<String, String> queryParamsMap = new HashMap<>();
Map<String, String> paramsMap = new HashMap<>();
Map<String, String> headerParamsMap = new HashMap<>();
List<String> headerLinesList = new ArrayList<>();
private BasicParamsInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
// process header params inject
Headers.Builder headerBuilder = request.headers().newBuilder();
if (headerParamsMap.size() > 0) {
Iterator iterator = headerParamsMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
headerBuilder.add((String) entry.getKey(), (String) entry.getValue());
}
}
if (headerLinesList.size() > 0) {
for (String line: headerLinesList) {
headerBuilder.add(line);
}
}
requestBuilder.headers(headerBuilder.build());
// process header params end
// process queryParams inject whatever it's GET or POST
if (queryParamsMap.size() > 0) {
injectParamsIntoUrl(request, requestBuilder, queryParamsMap);
}
// process header params end
// process post body inject
if (request.method().equals("POST") && request.body().contentType().subtype().equals("x-www-form-urlencoded")) {
FormBody.Builder formBodyBuilder = new FormBody.Builder();
if (paramsMap.size() > 0) {
Iterator iterator = paramsMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue());
}
}
RequestBody formBody = formBodyBuilder.build();
String postBodyString = bodyToString(request.body());
postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody);
requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString));
} else { // can't inject into body, then inject into url
injectParamsIntoUrl(request, requestBuilder, paramsMap);
}
request = requestBuilder.build();
return chain.proceed(request);
}
// func to inject params into url
private void injectParamsIntoUrl(Request request, Request.Builder requestBuilder, Map<String, String> paramsMap) {
HttpUrl.Builder httpUrlBuilder = request.url().newBuilder();
if (paramsMap.size() > 0) {
Iterator iterator = paramsMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
httpUrlBuilder.addQueryParameter((String) entry.getKey(), (String) entry.getValue());
}
}
requestBuilder.url(httpUrlBuilder.build());
}
private static String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
if(copy != null)
copy.writeTo(buffer);
else
return "";
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
public static class Builder {
BasicParamsInterceptor interceptor;
public Builder() {
interceptor = new BasicParamsInterceptor();
}
public Builder addParam(String key, String value) {
interceptor.paramsMap.put(key, value);
return this;
}
public Builder addParamsMap(Map<String, String> paramsMap) {
interceptor.paramsMap.putAll(paramsMap);
return this;
}
public Builder addHeaderParam(String key, String value) {
interceptor.headerParamsMap.put(key, value);
return this;
}
public Builder addHeaderParamsMap(Map<String, String> headerParamsMap) {
interceptor.headerParamsMap.putAll(headerParamsMap);
return this;
}
public Builder addHeaderLine(String headerLine) {
int index = headerLine.indexOf(":");
if (index == -1) {
throw new IllegalArgumentException("Unexpected header: " + headerLine);
}
interceptor.headerLinesList.add(headerLine);
return this;
}
public Builder addHeaderLinesList(List<String> headerLinesList) {
for (String headerLine: headerLinesList) {
int index = headerLine.indexOf(":");
if (index == -1) {
throw new IllegalArgumentException("Unexpected header: " + headerLine);
}
interceptor.headerLinesList.add(headerLine);
}
return this;
}
public Builder addQueryParam(String key, String value) {
interceptor.queryParamsMap.put(key, value);
return this;
}
public Builder addQueryParamsMap(Map<String, String> queryParamsMap) {
interceptor.queryParamsMap.putAll(queryParamsMap);
return this;
}
public BasicParamsInterceptor build() {
return interceptor;
}
}
}
只要像上面一樣配置就行了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Flutter 使用cached_image_network優(yōu)化圖片加載體驗(yàn)
在 Flutter 中,cached_image_network 即提供了緩存網(wǎng)絡(luò)圖片功能,同時還提供了豐富的加載過程指示。本文就來看下cached_image_network的具體使用2021-05-05
android實(shí)現(xiàn)icon動態(tài)旋轉(zhuǎn)效果
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)icon動態(tài)旋轉(zhuǎn)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07
RecyclerView優(yōu)雅實(shí)現(xiàn)復(fù)雜列表布局
這篇文章主要為大家詳細(xì)介紹了RecyclerView優(yōu)雅實(shí)現(xiàn)復(fù)雜列表布局,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-11-11
Android 簡單跳轉(zhuǎn)頁面工具的實(shí)例詳解
這篇文章主要介紹了Android 簡單跳轉(zhuǎn)頁面工具的實(shí)例詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03
Android DataBinding單向數(shù)據(jù)綁定深入探究
看了谷歌官方文章確實(shí)寫的太簡略了,甚至看完之后有很多地方還不知道怎么回事兒或者怎么用,那么接下來我將通過文章全面介紹一下DataBinding單向數(shù)據(jù)綁定2022-11-11

