XHttp2 一個功能強悍的網絡請求庫,使用RxJava2 + Retrofit2 + OKHttp進行組裝

XHttp2

api
I
Star

一個功能強悍的網絡請求庫,使用RxJava2 + Retrofit2 + OKHttp組合進行封裝。還不趕忙點擊使用說明文檔,體驗一下吧!java

關於我

github
csdn

特徵

  • 支持默認、全局、局部三個層次的配置功能。
  • 支持動態配置和自定義底層框架Okhttpclient、Retrofit.
  • 加入基礎ApiService,減小Api冗餘。
  • 支持多種方式訪問網絡GET、POST、PUT、DELETE等請求協議。
  • 支持網絡緩存,六種緩存策略可選,涵蓋大多數業務場景。
  • 支持固定添加header和動態添加header。
  • 支持添加全局參數和動態添加局部參數。
  • 支持文件下載、多文件上傳和表單提交數據。
  • 支持文件請求、上傳、下載的進度回調、錯誤回調,也能夠自定義回調。
  • 支持任意數據結構的自動解析。
  • 支持添加動態參數例如timeStamp時間戳、token、簽名sign。
  • 支持自定義的擴展API。
  • 支持多個請求合併。
  • 支持Cookie管理。
  • 支持異步、同步請求。
  • 支持Https、自簽名網站Https的訪問、雙向驗證。
  • 支持失敗重試機制,能夠指定重試次數、重試間隔時間。
  • 支持根據key刪除網絡緩存和清空網絡緩存。
  • 提供默認的標準ApiResult(遵循OpenApi格式)解析和回調,而且可自定義ApiResult。
  • 支持取消數據請求,取消訂閱,帶有對話框的請求不須要手動取消請求,對話框消失會自動取消請求。
  • 支持請求數據結果採用回調和訂閱兩種方式。
  • 提供"默認API"、"接口協議"以及"統一請求實體"三種方式進行網絡請求,支持自定義網絡請求協議。
  • 返回結果和異常統一處理,支持自定義異常處理。
  • 結合RxJava,線程切換靈活。
  • 請求實體支持註解配置,配置網絡請求接口的url、是否須要驗證token以及請求參數的key。
  • 擁有統一的網絡請求取消機制。

一、演示(請star支持)

1.一、Demo演示動畫

這裏寫圖片描述

1.二、Demo下載

downloads

這裏寫圖片描述

1.三、api服務安裝

服務端的搭建詳細請點擊查看react

二、如何使用

目前支持主流開發工具AndroidStudio的使用,直接配置build.gradle,增長依賴便可.android

2.一、Android Studio導入方法,添加Gradle依賴

1.先在項目根目錄的 build.gradle 的 repositories 添加:git

allprojects {
     repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}
複製代碼

2.而後在dependencies添加:github

dependencies {
  ...
  implementation 'com.github.xuexiangjys:XHttp2:1.0.0'
  implementation 'com.google.code.gson:gson:2.8.2'
  implementation 'com.squareup.okhttp3:okhttp:3.10.0'
  implementation 'io.reactivex.rxjava2:rxjava:2.1.12'
  implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
}
複製代碼

3.在Application中初始化XHttpSDKjson

XHttpSDK.init(this);   //初始化網絡請求框架,必須首先執行
XHttpSDK.debug("XHttp");  //須要調試的時候執行
XHttpSDK.setBaseUrl(SettingSPUtils.getInstance().getApiURL());  //設置網絡請求的基礎地址
複製代碼

4.全局初始化配置(非必要)api

除了上述的操做之外,你還可使用XHttp.getInstance()對網絡請求框架進行全局性參數配置,配置一些公用默認的參數,這樣咱們就不須要爲每一個請求都進行設置。方法以下:緩存

方法名 備註
debug 設置日誌的打印模式
setBaseUrl 設置全局baseUrl
setSubUrl 設置全局subUrl
setReadTimeOut 設置全局讀取超時時間
setWriteTimeOut 設置全局寫入超時時間
setConnectTimeout 設置全局鏈接超時時間
setTimeout 設置全局超時時間
setRetryCount 設置全局超時重試次數
setRetryDelay 設置全局超時重試延遲時間
setRetryIncreaseDelay 設置全局超時重試延遲疊加時間
setCacheMode 設置全局的緩存模式
setIsDiskCache 設置是不是磁盤緩存
setMemoryMaxSize 設置內存緩存的最大數量
setCacheTime 設置全局的緩存過時時間
setCacheMaxSize 設置全局的磁盤緩存大小,默認50M
setCacheDirectory 設置全局緩存的路徑,默認是應用包下面的緩存
setCacheDiskConverter 設置全局緩存的轉換器
addCommonParams 添加全局公共請求參數
addCommonHeaders 添加全局公共請求參數
addInterceptor 添加全局攔截器
addNetworkInterceptor 添加全局網絡攔截器
setOkproxy 全局設置OkHttpClient的代理
setOkconnectionPool 設置全局OkHttpClient的請求鏈接池
setOkclient 全局爲Retrofit設置自定義的OkHttpClient
addConverterFactory 設置全局Converter.Factory,默認GsonConverterFactory.create()
addCallAdapterFactory 設置全局CallAdapter.Factory,默認RxJavaCallAdapterFactory.create()
setHostnameVerifier 設置https的全局訪問規則
setCertificates 設置https的全局自簽名證書
setCookieStore 設置全局cookie存取規則

如何進行網絡請求

一、使用XHttp默認api進行請求

1.使用XHttp.post、XHttp.get、XHttp.delete、XHttp.put、XHttp.downLoad構建請求。bash

2.修改request的請求參數。cookie

方法名 類型 默認值 備註
baseUrl String 設置該請求的baseUrl
timeOut long 10000 設置超時時間
accessToken boolean false 是否須要驗證token
threadType String 設置請求的線程調度類型
syncRequest boolean false 設置是不是同步請求(不開子線程)
onMainThread boolean true 請求完成後是否回到主線程
upJson String "" 上傳Json格式的數據請求
keepJson boolean false 返回保持json的形式
retryCount int 設置超時重試的次數
retryDelay int 設置超時重試的延遲時間
retryIncreaseDelay int 設置超時重試疊加延時
headers HttpHeaders 添加頭信息
params HttpParams 設置表單請求參數
cacheMode CacheMode CacheMode.NO_CACHE 設置緩存的模式

3.調用execute方法執行請求。execute通常有以下兩種方式:

  • execute(CallBack callBack): 直接回調結果。

  • execute(Class clazz)和execute(Type type): 回調Observable對象,可經過訂閱獲取到結果。

4.請求使用演示

XHttp.get("/user/getAllUser")
        .syncRequest(false) //異步請求
        .onMainThread(true) //回到主線程
        .execute(new SimpleCallBack<List<User>>() {
            @Override
            public void onSuccess(List<User> response) {
                refreshLayout.finishRefresh(true);
                if (response != null && response.size() > 0) {
                    mUserAdapter.refresh(response);
                    mLlStateful.showContent();
                } else {
                    mLlStateful.showEmpty();
                }
            }
            @Override
            public void onError(ApiException e) {
                refreshLayout.finishRefresh(false);
                mLlStateful.showError(e.getMessage(), null);
            }

        });
複製代碼
XHttp.post("/user/deleteUser")
        .params("userId", item.getUserId())
        .execute(Boolean.class)
        .subscribeWith(new TipRequestSubscriber<Boolean>() {
            @Override
            protected void onSuccess(Boolean aBoolean) {
                ToastUtils.toast("刪除成功!");
                setFragmentResult(RESULT_OK, null);
                popToBack();
            }
        });

複製代碼

二、使用XHttpRequest封裝的統一請求實體進行請求

在使用它以前,須要下載/定義對應的實體協議,以下:

@RequestParams(url = "/user/addUser", accessToken = false)
public static class UserService_AddUser extends XHttpRequest {

    /**
     *
     */
    public User request;

    @Override
    protected Boolean getResponseEntityType() {
        return null;
    }
}
複製代碼

1.註解說明

  • @RequestParams
註解參數 類型 默認值 備註
baseUrl String "" 設置該請求的baseUrl
url String "" 請求網絡接口地址
timeout long 15000 設置超時時間
accessToken boolean true 設置是否須要驗證token
cacheMode CacheMode CacheMode.NO_CACHE 設置請求的緩存模式
  • @ParamKey
註解參數 類型 默認值 備註
key String / 請求參數的key

2.使用XHttpSDK進行請求。

  • post(XHttpRequest xHttpRequest, boolean isSyncRequest, boolean toMainThread): 獲取PostRequest請求(使用實體參數名做爲請求Key)。

  • postToMain(XHttpRequest xHttpRequest): 獲取PostRequest請求(主線程->主線程)。

  • postToIO(XHttpRequest xHttpRequest): 獲取PostRequest請求(主線程->子線程)。

  • postInThread(XHttpRequest xHttpRequest): 獲取PostRequest請求(子線程->子線程)。

  • execute(XHttpRequest xHttpRequest, boolean isSyncRequest, boolean toMainThread) : 執行PostRequest請求,返回observable對象(使用實體參數名做爲請求Key)。

  • executeToMain(XHttpRequest xHttpRequest): 執行post請求,返回observable對象(主線程->主線程)

  • executeToMain(XHttpRequest xHttpRequest,BaseSubscriber<T> subscriber): 執行post請求並進行訂閱,返回訂閱信息(主線程->主線程)

3.請求使用演示。

XHttpRequest req = ApiProvider.getAddUserReq(getRandomUser());
XHttpSDK.executeToMain(req, new ProgressLoadingSubscriber<Boolean>(mIProgressLoader) {
    @Override
    public void onSuccess(Boolean aBoolean) {
        ToastUtils.toast("用戶添加成功!");
        mRefreshLayout.autoRefresh();
    }
});
複製代碼

三、使用XHttpProxy代理進行請求

在使用它以前,須要下載/定義對應的接口協議,以下:

/**
 * 訂單
 */
public interface IOrder {
    /**
     * 購買書
     *
     * @param bookId 用戶名
     * @param userId 密碼
     */
    @NetMethod(ParameterNames = {"bookId", "userId", "number"}, Url = "/order/addOrder/")
    Observable<Boolean> buyBook(int bookId, int userId, int number);
}
複製代碼

1.註解說明

  • @NetMethod
註解參數 類型 默認值 備註
ParameterNames String[] {} 參數名集合
BaseUrl String "" 設置該請求的baseUrl
Url String "" 請求網絡接口地址
Timeout long 10000 設置超時時間
AccessToken boolean true 設置是否須要驗證token
CacheMode CacheMode CacheMode.NO_CACHE 設置請求的緩存模式

2.使用XHttpProxy進行請求。

構建一個XHttpProxy,將定義的api接口傳入後,直接調用接口進行請求。

構造XHttpProxy須要傳入ThreadType,默認是ThreadType.TO_MAIN

  • TO_MAIN: executeToMain(main -> io -> main)

【注意】請確保網絡請求在主線程中【實質是異步請求(切換到io線程),且響應的線程又切換至主線程】

  • TO_IO: executeToIO(main -> io -> io)

【注意】請確保網絡請求在主線程中【實質是異步請求(切換到io線程),不過響應的線程不變,仍是以前請求的那個io線程】

  • IN_THREAD: executeInThread(io -> io -> io)

【注意】請確保網絡請求在子線程中才可使用該類型【實質是不作任何線程調度的同步請求】

3.請求使用演示。

//使用XHttpProxy進行接口代理請求
XHttpProxy.proxy(TestApi.IOrder.class)
        .buyBook(mBookAdapter.getItem(position).getBookId(), UserManager.getInstance().getUser().getUserId(), 1)
        .subscribeWith(new TipRequestSubscriber<Boolean>() {
            @Override
            public void onSuccess(Boolean aBoolean) {
                ToastUtils.toast("圖書購買" + (aBoolean ? "成功" : "失敗") + "!");
                mRefreshLayout.autoRefresh();
            }
        });
複製代碼

四、文件上傳和下載

1.文件上傳【multipart/form-data】

使用post的文件表單上傳。使用XHttp.post,而後使用params傳遞附帶的參數,使用uploadFile傳遞須要上傳的文件,使用示例以下:

mIProgressLoader.updateMessage("上傳中...");
XHttp.post("/book/uploadBookPicture")
        .params("bookId", book.getBookId())
        .uploadFile("file", FileUtils.getFileByPath(mPicturePath), new IProgressResponseCallBack() {
            @Override
            public void onResponseProgress(long bytesWritten, long contentLength, boolean done) {

            }
        }).execute(Boolean.class)
        .compose(RxLifecycle.with(this).<Boolean>bindToLifecycle())
        .subscribeWith(new ProgressLoadingSubscriber<Boolean>(mIProgressLoader) {
            @Override
            public void onSuccess(Boolean aBoolean) {
                mIsEditSuccess = true;
                ToastUtils.toast("圖片上傳" + (aBoolean ? "成功" : "失敗") + "!");
            }
        });
複製代碼

2.文件下載

使用XHttp.downLoad,傳入下載的地址url、保存文件的路徑以及文件名便可完成文件的下載,使用示例以下:

XHttp.downLoad(BookAdapter.getBookImgUrl(book))
        .savePath(PathUtils.getExtPicturesPath())
        .execute(new DownloadProgressCallBack<String>() {
            @Override
            public void onStart() {
                HProgressDialogUtils.showHorizontalProgressDialog(getContext(), "圖片下載中...", true);
            }

            @Override
            public void onError(ApiException e) {
                ToastUtils.toast(e.getMessage());
                HProgressDialogUtils.cancel();
            }

            @Override
            public void update(long bytesRead, long contentLength, boolean done) {
                HProgressDialogUtils.onLoading(contentLength, bytesRead); //更新進度條
            }

            @Override
            public void onComplete(String path) {
                ToastUtils.toast("圖片下載成功, 保存路徑:" + path);
                HProgressDialogUtils.cancel();
            }
        });
複製代碼

高階網絡請求操做

請求生命週期綁定

1.請求loading加載和請求生命週期綁定

在請求時,訂閱ProgressLoadingSubscriber或者ProgressLoadingCallBack,傳入請求消息加載者IProgressLoader,便可完成生命週期的綁定。示例以下:

XHttpRequest req = ApiProvider.getAddUserReq(getRandomUser());
    XHttpSDK.executeToMain(req, new ProgressLoadingSubscriber<Boolean>(mIProgressLoader) {
        @Override
        public void onSuccess(Boolean aBoolean) {
            ToastUtils.toast("用戶添加成功!");
            mRefreshLayout.autoRefresh();
        }
    });
複製代碼

2.網絡請求生命週期和Activity/Fragment生命週期綁定

(1)這裏須要依賴一下RxUtil2

implementation 'com.github.xuexiangjys:rxutil2:1.1.2'
複製代碼

(2)在所在的Activity的onCreate()下鎖定Activity.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    RxLifecycle.injectRxLifecycle(this);
}
複製代碼

(3)而後在請求中使用RxJava的compose的操做符進行綁定。

.compose(RxLifecycle.with(this).<Boolean>bindToLifecycle())
複製代碼

攔截器

日誌攔截器

(1)框架默認提供一個實現好的日誌攔截器HttpLoggingInterceptor,經過XHttpSDK.debug("XHttp");就能夠設置進去,它有5種打印模式

  • NONE: 不打印log

  • BASIC: 只打印"請求首行"和"響應首行"。

  • HEADERS: 打印請求和響應的全部 Header

  • PARAM: 只打印請求和響應參數

  • BODY: 打印全部數據(默認是這種)

(2)若是須要對網絡請求的相關參數進行自定義記錄的話,能夠繼承HttpLoggingInterceptor實現一個本身的網絡請求日誌攔截器,重寫logForRequestlogForResponse兩個方法便可。

(3)設置自定義的日誌攔截器.

XHttpSDK.debug(new CustomLoggingInterceptor());
複製代碼

動態參數添加攔截器

有時候,咱們須要對全部請求添加一些固定的請求參數,可是這些參數的值又是變化的,這個時候咱們就須要動態添加請求參數【例如,請求的token、時間戳以及簽名等】

(1)繼承BaseDynamicInterceptor,實現updateDynamicParams方法,以下:

@Override
protected TreeMap<String, Object> updateDynamicParams(TreeMap<String, Object> dynamicMap) {
    if (isAccessToken()) {//是否添加token
        dynamicMap.put("token", TokenManager.getInstance().getToken());
    }
    if (isSign()) {//是否添加簽名
        dynamicMap.put("sign", TokenManager.getInstance().getSign());
    }
    if (isTimeStamp()) {//是否添加請求時間戳
        dynamicMap.put("timeStamp", DateUtils.getNowMills());
    }
    return dynamicMap;//dynamicMap:是原有的全局參數+局部參數+新增的動態參數
}
複製代碼

(2)設置動態參數添加攔截器。

XHttpSDK.addInterceptor(new CustomDynamicInterceptor()); //設置動態參數添加攔截器
複製代碼

失效請求校驗攔截器

當服務端返回一些獨特的錯誤碼(通常是token校驗錯誤、失效,請求過於頻繁等),須要咱們進行全局性的攔截捕獲,並做出相應的響應時,咱們就須要定義一個特殊的攔截器求處理這些請求。

(1)繼承BaseExpiredInterceptor,實現isResponseExpiredresponseExpired方法,以下:

/**
 * 判斷是不是失效的響應
 *
 * @param oldResponse
 * @param bodyString
 * @return {@code true} : 失效 <br>  {@code false} : 有效
 */
@Override
protected ExpiredInfo isResponseExpired(Response oldResponse, String bodyString) {
    int code = JSONUtils.getInt(bodyString, ApiResult.CODE, 0);
    ExpiredInfo expiredInfo = new ExpiredInfo(code);
    switch (code) {
        case TOKEN_INVALID:
        case TOKEN_MISSING:
            expiredInfo.setExpiredType(KEY_TOKEN_EXPIRED)
                    .setBodyString(bodyString);
            break;
        case AUTH_ERROR:
            expiredInfo.setExpiredType(KEY_UNREGISTERED_USER)
                    .setBodyString(bodyString);
            break;
        default:
            break;
    }
    return expiredInfo;
}

/**
 * 失效響應的處理
 *
 * @return 獲取新的有效請求響應
 */
@Override
protected Response responseExpired(Response oldResponse, Chain chain, ExpiredInfo expiredInfo) {
    switch(expiredInfo.getExpiredType()) {
        case KEY_TOKEN_EXPIRED:
            User user = TokenManager.getInstance().getLoginUser();
            if (user != null) {
                final boolean[] isGetNewToken = {false};
                HttpLog.e("正在從新獲取token...");
                XHttpProxy.proxy(ThreadType.IN_THREAD, TestApi.IAuthorization.class)
                        .login(user.getLoginName(), user.getPassword())
                        .subscribeWith(new NoTipRequestSubscriber<LoginInfo>() {
                            @Override
                            protected void onSuccess(LoginInfo loginInfo) {
                                TokenManager.getInstance()
                                        .setToken(loginInfo.getToken())
                                        .setLoginUser(loginInfo.getUser());
                                isGetNewToken[0] = true;
                                HttpLog.e("從新獲取token成功:" + loginInfo.getToken());
                            }
                        });
                if (isGetNewToken[0]) {
                    try {
                        HttpLog.e("使用新的token從新進行請求...");
                        return chain.proceed(HttpUtils.updateUrlParams(chain.request(), "token", TokenManager.getInstance().getToken()));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                XRouter.getInstance().build("/xhttp/login").navigation();
                return HttpUtils.getErrorResponse(oldResponse, expiredInfo.getCode(), "請先進行登陸!");
            }
            break;
        case KEY_UNREGISTERED_USER:
            return HttpUtils.getErrorResponse(oldResponse, expiredInfo.getCode(), "非法用戶登陸!");
        default:
            break;
    }
    return null;
}

複製代碼

(2)設置失效請求校驗攔截器。

XHttpSDK.addInterceptor(new CustomExpiredInterceptor()); //請求失效校驗攔截器
複製代碼

自定義API請求

自定義請求響應的API結構

若是你不想使用默認的ApiResult實體做爲統一的服務端響應實體,好比說你想要下面的響應實體:

private int errorCode; //請求的錯誤碼
private String errorInfo; //請求錯誤的緣由描述
private T result; //請求的結果
private long timeStamp; //服務端返回的時間戳
複製代碼

(1)首先,繼承ApiResult實體,重寫其getCodegetMsgisSuccessgetData方法。

public class CustomApiResult<T> extends ApiResult<T> {

    private int errorCode;
    private String errorInfo;
    private T result;
    private long timeStamp;

    public int getErrorCode() {
        return errorCode;
    }

    public CustomApiResult<T> setErrorCode(int errorCode) {
        this.errorCode = errorCode;
        return this;
    }

    public String getErrorInfo() {
        return errorInfo;
    }

    public CustomApiResult<T> setErrorInfo(String errorInfo) {
        this.errorInfo = errorInfo;
        return this;
    }

    public T getResult() {
        return result;
    }

    public CustomApiResult<T> setResult(T result) {
        this.result = result;
        return this;
    }

    public long getTimeStamp() {
        return timeStamp;
    }

    public CustomApiResult<T> setTimeStamp(long timeStamp) {
        this.timeStamp = timeStamp;
        return this;
    }

    @Override
    public int getCode() {
        return errorCode;
    }

    @Override
    public String getMsg() {
        return errorInfo;
    }

    @Override
    public boolean isSuccess() {
        return errorCode == 0;
    }

    @Override
    public T getData() {
        return result;
    }

    @Override
    public String toString() {
        return "ApiResult{" +
                "errorCode='" + errorCode + '\'' + ", errorInfo='" + errorInfo + '\'' + ", timeStamp='" + timeStamp + '\'' +
                ", result=" + result +
                '}';
    }
}
複製代碼

(2)進行請求的時候使用execute(CallBackProxy)或者execute(CallClazzProxy方法進行請求

XHttp.get("/test/testCustomResult")
            .execute(new CallBackProxy<CustomApiResult<Boolean>, Boolean>(new TipRequestCallBack<Boolean>() {
                @Override
                public void onSuccess(Boolean response) throws Throwable {
                    ToastUtils.toast("請求成功:" + response);
                }
            }){});
複製代碼

若是你以爲寫一長串比較麻煩,你能夠自定義請求繼承你須要的請求方式,例如這裏是get請求,咱們能夠這樣寫:

public class CustomGetRequest extends GetRequest {

    public CustomGetRequest(String url) {
        super(url);
    }

    @Override
    public <T> Observable<T> execute(Type type) {
        return execute(new CallClazzProxy<CustomApiResult<T>, T>(type) {
        });
    }

    @Override
    public <T> Disposable execute(CallBack<T> callBack) {
        return execute(new CallBackProxy<CustomApiResult<T>, T>(callBack) {
        });
    }
}
複製代碼

而後咱們就能夠用自定義的CustomGetRequest進行請求了,是否是簡化了不少呢。

new CustomGetRequest("/test/testCustomResult")
        .execute(new TipRequestCallBack<Boolean>() {
            @Override
            public void onSuccess(Boolean response) throws Throwable {
                ToastUtils.toast("請求成功:" + response);
            }
        });
複製代碼

使用自定義的retrofit接口

若是你對retrofit接口情有獨鍾,我也提供了相應的api方便調用.

1.定義retrofit接口。例如我定義一個用戶添加的接口:

/**
 * 使用的是retrofit的接口定義
 */
public interface UserService {
    @POST("/user/registerUser/")
    @Headers({"Content-Type: application/json", "Accept: application/json"})
    Observable<ApiResult<Boolean>> registerUser(@Body RequestBody jsonBody);


    @POST("/user/registerUser/")
    @Headers({"Content-Type: application/json", "Accept: application/json"})
    Observable<ApiResult> register(@Body RequestBody jsonBody);
}
複製代碼

2.使用XHttp.custom()構建的CustomRequest進行請求,你可使用apiCallcall進行請求。

  • apiCall: 針對的是retrofit定義的接口,返回的是Observable<ApiResult>的狀況。對於上面定義的第一個接口registerUser

  • call: 針對的是retrofit定義的接口,返回的是Observable的狀況。對於上面定義的第二個接口register

使用示例以下:

CustomRequest request = XHttp.custom();
request.apiCall(request.create(TestApi.UserService.class)
        .registerUser(HttpUtils.getJsonRequestBody(UserManager.getInstance().getRandomUser())))
        .subscribeWith(new TipRequestSubscriber<Boolean>() {
            @Override
            protected void onSuccess(Boolean aBoolean) {
                ToastUtils.toast("添加用戶成功!");
            }
        });
複製代碼
CustomRequest request = XHttp.custom();
request.call(request.create(TestApi.UserService.class)
        .register(HttpUtils.getJsonRequestBody(UserManager.getInstance().getRandomUser())))
        .subscribeWith(new TipRequestSubscriber<ApiResult>() {
            @Override
            protected void onSuccess(ApiResult apiResult) {
                ToastUtils.toast("添加用戶成功!");
                showResult(JsonUtil.toJson(apiResult));
            }
        });
複製代碼

緩存策略

目前框架提供了以下8種緩存策略:

  • NO_CACHE: 不使用緩存(默認方式)

  • DEFAULT: 徹底按照HTTP協議的默認緩存規則,走OKhttp的Cache緩存

  • FIRST_REMOTE: 先請求網絡,請求網絡失敗後再加載緩存

  • FIRST_CACHE: 先加載緩存,緩存沒有再去請求網絡

  • ONLY_REMOTE: 僅加載網絡,但數據依然會被緩存

  • ONLY_CACHE: 只讀取緩存

  • CACHE_REMOTE: 先使用緩存,不論是否存在,仍然請求網絡,會回調兩次

  • CACHE_REMOTE_DISTINCT: 先使用緩存,不論是否存在,仍然請求網絡,會先把緩存回調給你,等網絡請求回來發現數據是同樣的就不會再返回,不然再返回(這樣作的目的是防止數據是同樣的你也須要刷新界面)

對於緩存的實現,提供了磁盤緩存LruDiskCache和內存緩存LruMemoryCache兩種實現,默認使用的是磁盤緩存。

(1)能夠先進行緩存的全局性配置,配置緩存的有效期、緩存大小,緩存路徑、序列化器等。

XHttp.getInstance()
        .setIsDiskCache(true) //設置使用磁盤緩存
        .setCacheTime(60 * 1000) //設置全局緩存有效期爲一分鐘
        .setCacheVersion(1) //設置全局緩存的版本
        .setCacheDirectory(Utils.getDiskCacheDir(this, "XHttp")) //設置全局緩存保存的目錄路徑
        .setCacheMode(CacheMode.NO_CACHE) //設置全局的緩存策略
        .setCacheDiskConverter(new GsonDiskConverter())//默認緩存使用序列化轉化
        .setCacheMaxSize(50 * 1024 * 1024);//設置緩存大小爲50M
複製代碼

(2)在進行請求的時候,設置緩存模式和緩存的key便可。以下:

XHttp.get("/book/getAllBook")
        .timeOut(10 * 1000)//測試局部超時10s
        .cacheMode(mCacheMode)
        .cacheKey(CACHE_KEY)//緩存key
        .retryCount(5)//重試次數
        .cacheTime(5 * 60)//緩存時間300s,默認-1永久緩存  okhttp和自定義緩存都起做用
        .cacheDiskConverter(new GsonDiskConverter())//默認使用的是 new SerializableDiskConverter();
        .timeStamp(true)
        .execute(new ProgressLoadingCallBack<CacheResult<List<Book>>>(mIProgressLoader) {
            @Override
            public void onSuccess(CacheResult<List<Book>> cacheResult) {
                ToastUtils.toast("請求成功!");
                String from;
                if (cacheResult.isFromCache) {
                    from = "我來自緩存";
                } else {
                    from = "我來自遠程網絡";
                }
                showResult(from + "\n" + JsonUtil.toJson(cacheResult.data));
            }

            @Override
            public void onError(ApiException e) {
                super.onError(e);
                ToastUtils.toast(e.getDisplayMessage());
            }
        });
複製代碼

混淆配置

#XHttp2
-keep class com.xuexiang.xhttp2.model.** { *; }
-keep class com.xuexiang.xhttp2.cache.model.** { *; }
-keep class com.xuexiang.xhttp2.cache.stategy.**{*;}
-keep class com.xuexiang.xhttp2.annotation.** { *; }

#okhttp
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-dontwarn javax.annotation.**

# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Exceptions

# RxJava RxAndroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
    long producerIndex;
    long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode consumerNode;
}

#若是用到Gson解析包的,直接添加下面這幾行就能成功混淆,否則會報錯
-keepattributes Signature
-keep class com.google.gson.stream.** { *; }
-keepattributes EnclosingMethod
-keep class org.xz_sale.entity.**{*;}
-keep class com.google.gson.** {*;}
-keep class com.google.**{*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
複製代碼

特別感謝

github.com/zhou-you/Rx…

聯繫方式

這裏寫圖片描述
相關文章
相關標籤/搜索