android中Retrofit2.0的封裝:設計到請求前後的操作,比如新增請求頭,攔截請求頭,攔截返回體等
這裡關於android如何整合retrofit2.0就詳細介紹了,相信網路上也有很多的例子。
首先retrofit關於請求體如何加入的話,這裡使用註解就能解決大部分問題,而retrofit官網也給出了很多很好用的註解,只要在interface中宣告就行。
主要使用分為以下例子:
①新增retrofit庫依賴
②建立接受請求資料bean類
③建立用於請求的介面
④建立retrofit例項
⑤建立網路請求介面例項以及配置網路請求引數
⑥傳送網路請求
⑦處理返回資料
主要從第四步講起:
常規的retrofit例項建立是新建一個Builder()
比如:
Retrofit retrofit =new Retrofit.Builder() .baseUrl(“www.XXXXXX”) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();
這是常規建立例項,而我們知道,retrofit是基於okhttp的網路請求框架,所以我們封裝的時候,可以寫一個公有類,以下這是我的做法。
public class RetrofitHelper { /** 連線超時:10秒 */ public static final int TIME_OUT_CONNECT = 10 * 1000; /** 讀資料超時:10秒 */ public static final int TIME_OUT_READ = 10 * 1000; /** 轉換日誌輸出格式 */ private static HttpLoggingInterceptor.Logger mLogger = new MyHttpLogger(); private static OkHttpClient mOkHttpClient; //cookie儲存 public static ConcurrentHashMap<String, List<Cookie>> cookieStore; /** * 獲取帶有json轉換器的Retrofit物件,如果不需要json轉換器請使用 * buildRetrofit(String baseUrl, boolean isNeedGsonConverter)方法獲取 * */ public static Retrofit buildRetrofit(String baseUrl) { return buildRetrofit(baseUrl, true); } /** * 構建統一封裝的Retrofit物件 * * @param baseUrl * @param isNeedGsonConverter 是否需要gson轉換器 * @return Retrofit物件 */ public static Retrofit buildRetrofit(String baseUrl, boolean isNeedGsonConverter) { Retrofit.Builder builder = new Retrofit.Builder() .client(getSingleOkHttpClient()) .baseUrl(baseUrl); if (isNeedGsonConverter) { builder.addConverterFactory(GsonConverterFactory.create()); } return builder.build(); } /** * 獲取OkHttpClient物件,用於需要定製OkHttpClient的情況。 * 該物件已經做了基本的封裝,使用者可以在此基礎上做進一步定製。 * 用法: * Retrofit retrofit = RetrofitHelper.buildRetrofit("baseUrl"); * OkHttpClient okHttpClient = RetrofitHelper.getmOkHttpClient(); * ... // 對okHttpClient做一些個性化定製 * retrofit = retrofit.newBuilder().client(okHttpClient).build(); //重新設定定製好的client * ... //繼續後續操作 * <p> * 通常情況下不需要獲取OkHttpClient物件,直接使用buildRetrofit()方法返回的Retrofit物件即可。 * * @return */ public static OkHttpClient getmOkHttpClient() { return buildClient(); } /** * 獲取單例的okHttpClient物件 * * @return */ private synchronized static OkHttpClient getSingleOkHttpClient() { if (mOkHttpClient == null) { mOkHttpClient = buildClient(); } return mOkHttpClient; } /** * 構建統一封裝的OkHttpClient物件, * 該物件增加了日誌攔截器及連線超時等引數 * * @return */ private static OkHttpClient buildClient() { // 日誌攔截器 HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(mLogger); if(cookieStore==null){ cookieStore = new ConcurrentHashMap<>(); } logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient.Builder builder = new OkHttpClient().newBuilder() .connectTimeout(TIME_OUT_CONNECT, TimeUnit.MILLISECONDS) .readTimeout(TIME_OUT_READ, TimeUnit.MILLISECONDS) .cookieJar(new CookieJar() { //cookie攔截儲存 @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { BaseActivity.setCookies(cookies); Log.i("狀態","Cookie保留成功"); Log.i("cooike為",BaseActivity.getCookies().toString()); } @Override public List<Cookie> loadForRequest(HttpUrl url) { Log.i("cooike為",BaseActivity.getCookies().toString()); Log.i("狀態","Cookie傳送"); return BaseActivity.getCookies(); } }) .addNetworkInterceptor(logInterceptor); return builder.build(); } /** * 將http報文中的json字串格式化並使用com.orhanobut.logger.Logger日誌系統列印日誌的類 * */ private static class MyHttpLogger implements HttpLoggingInterceptor.Logger { StringBuilder mMessage = new StringBuilder(); @Override public void log(String message) { // 列印請求或者響應報文中的每一行都會呼叫此方法,所以用一個StringBuilder把它們串起來 // 以{}或者[]形式的說明是響應結果的json資料,需要進行格式化 boolean isJsonStr = (message.startsWith("{") && message.endsWith("}")) || (message.startsWith("[") && message.endsWith("]")); if (isJsonStr) { message = CommonUtils.formatJsonString(message); } mMessage.append(message.concat("\n")); // 響應結束,列印整條日誌 if (message.startsWith("<-- END HTTP")) { Logger.d(mMessage.toString()); Logger.d("我是小尾巴"); mMessage.setLength(0); } } } }
接下來是對這個基礎類的講解,首先宣告的是幾個限制常量,用在okhttp中的超時設定中。接著是日誌列印,我後面在傳送請求的時候都會打印出來請求體與返回體,接著是一個cookie的儲存,坑爹的是因為後臺框架使用的是給WEB用的,登入狀態用的是session來儲存,後續請求也都是,所以在這裡我將第一次登入獲取到的session儲存起來並在後面需要的時候就使用上。後面我在建立例項的時候,設定選擇與不選擇gson轉換器的模式。
接下來講的就是重點:
在new一個retrofit的builder的時候會設定client,這裡我將client專門拿出來定製
/** * 構建統一封裝的OkHttpClient物件, * 該物件增加了日誌攔截器及連線超時等引數 * * @return */ private static OkHttpClient buildClient() { // 日誌攔截器 HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(mLogger); if(cookieStore==null){ cookieStore = new ConcurrentHashMap<>(); } logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient.Builder builder = new OkHttpClient().newBuilder() .connectTimeout(TIME_OUT_CONNECT, TimeUnit.MILLISECONDS) .readTimeout(TIME_OUT_READ, TimeUnit.MILLISECONDS) .cookieJar(new CookieJar() { //cookie攔截儲存 @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { BaseActivity.setCookies(cookies); Log.i("狀態","Cookie保留成功"); Log.i("cooike為",BaseActivity.getCookies().toString()); } @Override public List<Cookie> loadForRequest(HttpUrl url) { Log.i("cooike為",BaseActivity.getCookies().toString()); Log.i("狀態","Cookie傳送"); return BaseActivity.getCookies(); } }) .addNetworkInterceptor(logInterceptor); return builder.build(); }
在這上面我們設定了超時限制,以及cookie的儲存以及cookie的傳送。
以上是對okhttp的一些修飾
接下來我要講的是關於retrofit返回狀態碼的攔截,主要操作的是第六步,傳送網路請求的時候。
常規操作是這樣的:
//傳送非同步請求
Call.enqueue(new Callback<Bean>(){
//成功時回撥
Public void onResponse(Call<Bean> call,Response<Bean> response){
Response.body().show();
}
//失敗時回撥
Public void onFailure(Call<Bean> call,Throwable throwable) {
System.out.println(“連線失敗”);
}
});
以上是我們的常規做法,直接使用已有的callback類
我實現的方法是使用自定義的Callback並接入callback介面類。
首先先定義自己的callback:
package com.b2bwings.framework.network;
import android.util.Log;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Created by xuweijie
* on 2018/7/16 0016.
*/
public final class MyCallBack<T> implements Callback<T> {
/** 公共事務處理器 */
private static ICommonProcessor processor;
/** 網路請求回撥介面 */
private LoadDataCallBack loadDataCallBack;
public MyCallBack(LoadDataCallBack loadDataCallBack) {
this.loadDataCallBack = loadDataCallBack;
}
@Override
public void onFailure(Call<T> call, Throwable t) {
// 這裡可以對錯誤做統一的處理,目前只輸出錯誤日誌,子類可以重寫此方法作進一步處理
String url = call.request().url().toString();
}
@Override
public void onResponse(Call<T> call, Response<T> response) {
switch (response.code()) {
case 401:
// 401 代表登入失效(登入session失效)
if (processor != null) {
Log.d("狀態","統一處理401錯誤");
processor.process401();
} else {
Log.w("狀態","401錯誤,未設定公共處理器");
}
return;
//暫未設定錯誤碼攔截器
default:
break;
}
loadDataCallBack.onSuccess(response);
}
/**
* 設定公共處理器
*
* @param iCommonProcessor
*/
public static void setCommonProcessor(ICommonProcessor iCommonProcessor) {
processor = iCommonProcessor;
}
}
以及攔截介面
/**
* Created by xuweijie
* on 2018/7/13 0013.
*/
public interface ICommonProcessor {
/**
* 處理401錯誤,即登入失效
*/
void process401();
}
//載入資料回撥介面
public interface LoadDataCallBack<T> {
/**
* 載入資料成功
*
* @param response 返回的資料
*/
void onSuccess(Response<T> response);
/**
* 載入資料失敗
*
* @param throwable 錯誤資訊
*/
void onError(Throwable throwable);
}
其中在onResponse響應中,處理完攔截器之後就會回撥onSuccedd回撥。
以上是進行了狀態碼401的攔截。
最後要注意的是,必須在使用到攔截器的地方的進行設定
即:
MyCallBack.setCommonProcessor(this);
以上就是我對retrofit的一些封裝,實現了返回提中cookie的攔截,以及返回體狀態碼的統一處理。
如果大家有什麼疑問或者意見,歡迎批評指正