1. 程式人生 > >android中Retrofit2.0的封裝:設計到請求前後的操作,比如新增請求頭,攔截請求頭,攔截返回體等

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一個retrofitbuilder的時候會設定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的攔截,以及返回體狀態碼的統一處理。

如果大家有什麼疑問或者意見,歡迎批評指正