XHttp2
一個功能強悍的網(wǎng)絡(luò)請求庫女器,使用RxJava2 + Retrofit2 + OKHttp組合進(jìn)行封裝酸役。還不趕緊點擊使用說明文檔,體驗一下吧驾胆!
特征
- 支持默認(rèn)涣澡、全局、局部三個層次的配置功能丧诺。
- 支持動態(tài)配置和自定義底層框架Okhttpclient入桂、Retrofit.
- 加入基礎(chǔ)ApiService,減少Api冗余驳阎。
- 支持多種方式訪問網(wǎng)絡(luò)GET抗愁、POST馁蒂、PUT、DELETE等請求協(xié)議蜘腌。
- 支持網(wǎng)絡(luò)緩存,六種緩存策略可選,涵蓋大多數(shù)業(yè)務(wù)場景沫屡。
- 支持固定添加header和動態(tài)添加header。
- 支持添加全局參數(shù)和動態(tài)添加局部參數(shù)撮珠。
- 支持文件下載沮脖、多文件上傳和表單提交數(shù)據(jù)。
- 支持文件請求芯急、上傳勺届、下載的進(jìn)度回調(diào)、錯誤回調(diào)志于,也可以自定義回調(diào)涮因。
- 支持任意數(shù)據(jù)結(jié)構(gòu)的自動解析废睦。
- 支持添加動態(tài)參數(shù)例如timeStamp時間戳伺绽、token、簽名sign嗜湃。
- 支持自定義的擴展API奈应。
- 支持多個請求合并。
- 支持Cookie管理购披。
- 支持異步杖挣、同步請求阵苇。
- 支持Https酪术、自簽名網(wǎng)站Https的訪問、雙向驗證冒版。
- 支持失敗重試機制筐乳,可以指定重試次數(shù)歌殃、重試間隔時間。
- 支持根據(jù)key刪除網(wǎng)絡(luò)緩存和清空網(wǎng)絡(luò)緩存蝙云。
- 提供默認(rèn)的標(biāo)準(zhǔn)ApiResult(遵循OpenApi格式)解析和回調(diào)氓皱,并且可自定義ApiResult。
- 支持取消數(shù)據(jù)請求勃刨,取消訂閱波材,帶有對話框的請求不需要手動取消請求,對話框消失會自動取消請求身隐。
- 支持請求數(shù)據(jù)結(jié)果采用回調(diào)和訂閱兩種方式廷区。
- 提供"默認(rèn)API"、"接口協(xié)議"以及"統(tǒng)一請求實體"三種方式進(jìn)行網(wǎng)絡(luò)請求贾铝,支持自定義網(wǎng)絡(luò)請求協(xié)議躲因。
- 返回結(jié)果和異常統(tǒng)一處理早敬,支持自定義異常處理。
- 結(jié)合RxJava大脉,線程切換靈活搞监。
- 請求實體支持注解配置,配置網(wǎng)絡(luò)請求接口的url镰矿、是否需要驗證token以及請求參數(shù)的key琐驴。
- 擁有統(tǒng)一的網(wǎng)絡(luò)請求取消機制。
1秤标、演示(請star支持)
1.1绝淡、Demo演示動畫
1.2、Demo下載
1.3苍姜、api服務(wù)安裝
服務(wù)端的搭建詳細(xì)請點擊查看
2牢酵、如何使用
目前支持主流開發(fā)工具AndroidStudio的使用,直接配置build.gradle衙猪,增加依賴即可.
2.1馍乙、Android Studio導(dǎo)入方法,添加Gradle依賴
1.先在項目根目錄的 build.gradle 的 repositories 添加:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
2.然后在dependencies添加:
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中初始化XHttpSDK
XHttpSDK.init(this); //初始化網(wǎng)絡(luò)請求框架垫释,必須首先執(zhí)行
XHttpSDK.debug("XHttp"); //需要調(diào)試的時候執(zhí)行
XHttpSDK.setBaseUrl(SettingSPUtils.getInstance().getApiURL()); //設(shè)置網(wǎng)絡(luò)請求的基礎(chǔ)地址
4.全局初始化配置(非必要)
除了上述的操作以外丝格,你還可以使用XHttp.getInstance()
對網(wǎng)絡(luò)請求框架進(jìn)行全局性參數(shù)配置,配置一些公用默認(rèn)的參數(shù)棵譬,這樣我們就不需要為每個請求都進(jìn)行設(shè)置显蝌。方法如下:
方法名 | 備注 |
---|---|
debug | 設(shè)置日志的打印模式 |
setBaseUrl | 設(shè)置全局baseUrl |
setSubUrl | 設(shè)置全局subUrl |
setReadTimeOut | 設(shè)置全局讀取超時時間 |
setWriteTimeOut | 設(shè)置全局寫入超時時間 |
setConnectTimeout | 設(shè)置全局連接超時時間 |
setTimeout | 設(shè)置全局超時時間 |
setRetryCount | 設(shè)置全局超時重試次數(shù) |
setRetryDelay | 設(shè)置全局超時重試延遲時間 |
setRetryIncreaseDelay | 設(shè)置全局超時重試延遲疊加時間 |
setCacheMode | 設(shè)置全局的緩存模式 |
setIsDiskCache | 設(shè)置是否是磁盤緩存 |
setMemoryMaxSize | 設(shè)置內(nèi)存緩存的最大數(shù)量 |
setCacheTime | 設(shè)置全局的緩存過期時間 |
setCacheMaxSize | 設(shè)置全局的磁盤緩存大小,默認(rèn)50M |
setCacheDirectory | 設(shè)置全局緩存的路徑,默認(rèn)是應(yīng)用包下面的緩存 |
setCacheDiskConverter | 設(shè)置全局緩存的轉(zhuǎn)換器 |
addCommonParams | 添加全局公共請求參數(shù) |
addCommonHeaders | 添加全局公共請求參數(shù) |
addInterceptor | 添加全局?jǐn)r截器 |
addNetworkInterceptor | 添加全局網(wǎng)絡(luò)攔截器 |
setOkproxy | 全局設(shè)置OkHttpClient的代理 |
setOkconnectionPool | 設(shè)置全局OkHttpClient的請求連接池 |
setOkclient | 全局為Retrofit設(shè)置自定義的OkHttpClient |
addConverterFactory | 設(shè)置全局Converter.Factory,默認(rèn)GsonConverterFactory.create() |
addCallAdapterFactory | 設(shè)置全局CallAdapter.Factory,默認(rèn)RxJavaCallAdapterFactory.create() |
setHostnameVerifier | 設(shè)置https的全局訪問規(guī)則 |
setCertificates | 設(shè)置https的全局自簽名證書 |
setCookieStore | 設(shè)置全局cookie存取規(guī)則 |
如何進(jìn)行網(wǎng)絡(luò)請求
1订咸、使用XHttp默認(rèn)api進(jìn)行請求
1.使用XHttp.post曼尊、XHttp.get、XHttp.delete脏嚷、XHttp.put骆撇、XHttp.downLoad構(gòu)建請求。
2.修改request的請求參數(shù)然眼。
方法名 | 類型 | 默認(rèn)值 | 備注 |
---|---|---|---|
baseUrl | String | / | 設(shè)置該請求的baseUrl |
timeOut | long | 10000 | 設(shè)置超時時間 |
accessToken | boolean | false | 是否需要驗證token |
threadType | String | / | 設(shè)置請求的線程調(diào)度類型 |
syncRequest | boolean | false | 設(shè)置是否是同步請求(不開子線程) |
onMainThread | boolean | true | 請求完成后是否回到主線程 |
upJson | String | "" | 上傳Json格式的數(shù)據(jù)請求 |
keepJson | boolean | false | 返回保持json的形式 |
retryCount | int | / | 設(shè)置超時重試的次數(shù) |
retryDelay | int | / | 設(shè)置超時重試的延遲時間 |
retryIncreaseDelay | int | / | 設(shè)置超時重試疊加延時 |
headers | HttpHeaders | / | 添加頭信息 |
params | HttpParams | / | 設(shè)置表單請求參數(shù) |
cacheMode | CacheMode | CacheMode.NO_CACHE | 設(shè)置緩存的模式 |
3.調(diào)用execute
方法執(zhí)行請求艾船。execute一般有如下兩種方式:
execute(CallBack callBack): 直接回調(diào)結(jié)果。
execute(Class clazz)和execute(Type type): 回調(diào)Observable<T>對象高每,可通過訂閱獲取到結(jié)果屿岂。
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();
}
});
2鲸匿、使用XHttpRequest封裝的統(tǒng)一請求實體進(jìn)行請求
在使用它之前爷怀,需要下載/定義對應(yīng)的實體協(xié)議,如下:
@RequestParams(url = "/user/addUser", accessToken = false)
public static class UserService_AddUser extends XHttpRequest {
/**
*
*/
public User request;
@Override
protected Boolean getResponseEntityType() {
return null;
}
}
1.注解說明
- @RequestParams
注解參數(shù) | 類型 | 默認(rèn)值 | 備注 |
---|---|---|---|
baseUrl | String | "" | 設(shè)置該請求的baseUrl |
url | String | "" | 請求網(wǎng)絡(luò)接口地址 |
timeout | long | 15000 | 設(shè)置超時時間 |
accessToken | boolean | true | 設(shè)置是否需要驗證token |
cacheMode | CacheMode | CacheMode.NO_CACHE | 設(shè)置請求的緩存模式 |
- @ParamKey
注解參數(shù) | 類型 | 默認(rèn)值 | 備注 |
---|---|---|---|
key | String | / | 請求參數(shù)的key |
2.使用XHttpSDK進(jìn)行請求带欢。
post(XHttpRequest xHttpRequest, boolean isSyncRequest, boolean toMainThread):
獲取PostRequest請求(使用實體參數(shù)名作為請求Key)运授。postToMain(XHttpRequest xHttpRequest):
獲取PostRequest請求(主線程->主線程)烤惊。postToIO(XHttpRequest xHttpRequest):
獲取PostRequest請求(主線程->子線程)。postInThread(XHttpRequest xHttpRequest):
獲取PostRequest請求(子線程->子線程)吁朦。execute(XHttpRequest xHttpRequest, boolean isSyncRequest, boolean toMainThread) :
執(zhí)行PostRequest請求柒室,返回observable對象(使用實體參數(shù)名作為請求Key)。executeToMain(XHttpRequest xHttpRequest)
:
執(zhí)行post請求逗宜,返回observable對象(主線程->主線程)executeToMain(XHttpRequest xHttpRequest雄右,BaseSubscriber<T> subscriber)
:
執(zhí)行post請求并進(jìn)行訂閱,返回訂閱信息(主線程->主線程)
3.請求使用演示纺讲。
XHttpRequest req = ApiProvider.getAddUserReq(getRandomUser());
XHttpSDK.executeToMain(req, new ProgressLoadingSubscriber<Boolean>(mIProgressLoader) {
@Override
public void onSuccess(Boolean aBoolean) {
ToastUtils.toast("用戶添加成功擂仍!");
mRefreshLayout.autoRefresh();
}
});
3、使用XHttpProxy代理進(jìn)行請求
在使用它之前熬甚,需要下載/定義對應(yīng)的接口協(xié)議逢渔,如下:
/**
* 訂單
*/
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
注解參數(shù) | 類型 | 默認(rèn)值 | 備注 |
---|---|---|---|
ParameterNames | String[] | {} | 參數(shù)名集合 |
BaseUrl | String | "" | 設(shè)置該請求的baseUrl |
Url | String | "" | 請求網(wǎng)絡(luò)接口地址 |
Timeout | long | 10000 | 設(shè)置超時時間 |
AccessToken | boolean | true | 設(shè)置是否需要驗證token |
CacheMode | CacheMode | CacheMode.NO_CACHE | 設(shè)置請求的緩存模式 |
2.使用XHttpProxy進(jìn)行請求。
構(gòu)建一個XHttpProxy乡括,將定義的api接口傳入后肃廓,直接調(diào)用接口進(jìn)行請求。
構(gòu)造XHttpProxy需要傳入ThreadType
,默認(rèn)是ThreadType.TO_MAIN
粟判。
- TO_MAIN: executeToMain(main -> io -> main)
【注意】請確保網(wǎng)絡(luò)請求在主線程中【實質(zhì)是異步請求(切換到io線程)亿昏,且響應(yīng)的線程又切換至主線程】
- TO_IO: executeToIO(main -> io -> io)
【注意】請確保網(wǎng)絡(luò)請求在主線程中【實質(zhì)是異步請求(切換到io線程)峦剔,不過響應(yīng)的線程不變档礁,還是之前請求的那個io線程】
- IN_THREAD: executeInThread(io -> io -> io)
【注意】請確保網(wǎng)絡(luò)請求在子線程中才可以使用該類型【實質(zhì)是不做任何線程調(diào)度的同步請求】
3.請求使用演示。
//使用XHttpProxy進(jìn)行接口代理請求
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();
}
});
4呻澜、文件上傳和下載
1.文件上傳【multipart/form-data】
使用post的文件表單上傳。使用XHttp.post
,然后使用params
傳遞附帶的參數(shù)惨险,使用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); //更新進(jìn)度條
}
@Override
public void onComplete(String path) {
ToastUtils.toast("圖片下載成功, 保存路徑:" + path);
HProgressDialogUtils.cancel();
}
});
高階網(wǎng)絡(luò)請求操作
請求生命周期綁定
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.網(wǎng)絡(luò)請求生命周期和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
的操作符進(jìn)行綁定。
.compose(RxLifecycle.with(this).<Boolean>bindToLifecycle())
攔截器
日志攔截器
(1)框架默認(rèn)提供一個實現(xiàn)好的日志攔截器HttpLoggingInterceptor
,通過XHttpSDK.debug("XHttp");
就可以設(shè)置進(jìn)去膀值,它有5種打印模式
NONE: 不打印log
BASIC: 只打印"請求首行"和"響應(yīng)首行"棍丐。
HEADERS: 打印請求和響應(yīng)的所有 Header
PARAM: 只打印請求和響應(yīng)參數(shù)
BODY: 打印所有數(shù)據(jù)(默認(rèn)是這種)
(2)如果需要對網(wǎng)絡(luò)請求的相關(guān)參數(shù)進(jìn)行自定義記錄的話误辑,可以繼承HttpLoggingInterceptor
實現(xiàn)一個自己的網(wǎng)絡(luò)請求日志攔截器,重寫logForRequest
和logForResponse
兩個方法即可歌逢。
(3)設(shè)置自定義的日志攔截器.
XHttpSDK.debug(new CustomLoggingInterceptor());
動態(tài)參數(shù)添加攔截器
有時候巾钉,我們需要對所有請求添加一些固定的請求參數(shù),但是這些參數(shù)的值又是變化的秘案,這個時候我們就需要動態(tài)添加請求參數(shù)【例如睛琳,請求的token、時間戳以及簽名等】
(1)繼承BaseDynamicInterceptor
踏烙,實現(xiàn)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:是原有的全局參數(shù)+局部參數(shù)+新增的動態(tài)參數(shù)
}
(2)設(shè)置動態(tài)參數(shù)添加攔截器。
XHttpSDK.addInterceptor(new CustomDynamicInterceptor()); //設(shè)置動態(tài)參數(shù)添加攔截器
失效請求校驗攔截器
當(dāng)服務(wù)端返回一些獨特的錯誤碼(一般是token校驗錯誤讨惩、失效辟癌,請求過于頻繁等),需要我們進(jìn)行全局性的攔截捕獲荐捻,并作出相應(yīng)的響應(yīng)時黍少,我們就需要定義一個特殊的攔截器求處理這些請求。
(1)繼承BaseExpiredInterceptor
处面,實現(xiàn)isResponseExpired
和responseExpired
方法厂置,如下:
/**
* 判斷是否是失效的響應(yīng)
*
* @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;
}
/**
* 失效響應(yīng)的處理
*
* @return 獲取新的有效請求響應(yīng)
*/
@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重新進(jìn)行請求...");
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(), "請先進(jìn)行登錄!");
}
break;
case KEY_UNREGISTERED_USER:
return HttpUtils.getErrorResponse(oldResponse, expiredInfo.getCode(), "非法用戶登錄魂角!");
default:
break;
}
return null;
}
(2)設(shè)置失效請求校驗攔截器昵济。
XHttpSDK.addInterceptor(new CustomExpiredInterceptor()); //請求失效校驗攔截器
自定義API請求
自定義請求響應(yīng)的API結(jié)構(gòu)
如果你不想使用默認(rèn)的ApiResult實體作為統(tǒng)一的服務(wù)端響應(yīng)實體,比如說你想要下面的響應(yīng)實體:
private int errorCode; //請求的錯誤碼
private String errorInfo; //請求錯誤的原因描述
private T result; //請求的結(jié)果
private long timeStamp; //服務(wù)端返回的時間戳
(1)首先野揪,繼承ApiResult
實體访忿,重寫其getCode
、getMsg
斯稳、isSuccess
和getData
方法海铆。
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)進(jìn)行請求的時候使用execute(CallBackProxy)
或者execute(CallClazzProxy
方法進(jìn)行請求
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
進(jìn)行請求了,是不是簡化了很多呢。
new CustomGetRequest("/test/testCustomResult")
.execute(new TipRequestCallBack<Boolean>() {
@Override
public void onSuccess(Boolean response) throws Throwable {
ToastUtils.toast("請求成功:" + response);
}
});
使用自定義的retrofit接口
如果你對retrofit接口情有獨鐘憎茂,我也提供了相應(yīng)的api方便調(diào)用.
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()
構(gòu)建的CustomRequest
進(jìn)行請求,你可以使用apiCall
和call
進(jìn)行請求唇辨。
apiCall: 針對的是retrofit定義的接口廊酣,返回的是Observable<ApiResult<T>>的情況。對于上面定義的第一個接口
registerUser
赏枚。call: 針對的是retrofit定義的接口亡驰,返回的是Observable<T>的情況晓猛。對于上面定義的第二個接口
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: 不使用緩存(默認(rèn)方式)
DEFAULT: 完全按照HTTP協(xié)議的默認(rèn)緩存規(guī)則凡辱,走OKhttp的Cache緩存
FIRST_REMOTE: 先請求網(wǎng)絡(luò)戒职,請求網(wǎng)絡(luò)失敗后再加載緩存
FIRST_CACHE: 先加載緩存,緩存沒有再去請求網(wǎng)絡(luò)
ONLY_REMOTE: 僅加載網(wǎng)絡(luò)透乾,但數(shù)據(jù)依然會被緩存
ONLY_CACHE: 只讀取緩存
CACHE_REMOTE: 先使用緩存洪燥,不管是否存在,仍然請求網(wǎng)絡(luò)乳乌,會回調(diào)兩次
CACHE_REMOTE_DISTINCT: 先使用緩存捧韵,不管是否存在,仍然請求網(wǎng)絡(luò)汉操,會先把緩存回調(diào)給你再来,等網(wǎng)絡(luò)請求回來發(fā)現(xiàn)數(shù)據(jù)是一樣的就不會再返回,否則再返回(這樣做的目的是防止數(shù)據(jù)是一樣的你也需要刷新界面)
對于緩存的實現(xiàn)磷瘤,提供了磁盤緩存LruDiskCache
和內(nèi)存緩存LruMemoryCache
兩種實現(xiàn)芒篷,默認(rèn)使用的是磁盤緩存。
(1)可以先進(jìn)行緩存的全局性配置采缚,配置緩存的有效期针炉、緩存大小,緩存路徑扳抽、序列化器等篡帕。
XHttp.getInstance()
.setIsDiskCache(true) //設(shè)置使用磁盤緩存
.setCacheTime(60 * 1000) //設(shè)置全局緩存有效期為一分鐘
.setCacheVersion(1) //設(shè)置全局緩存的版本
.setCacheDirectory(Utils.getDiskCacheDir(this, "XHttp")) //設(shè)置全局緩存保存的目錄路徑
.setCacheMode(CacheMode.NO_CACHE) //設(shè)置全局的緩存策略
.setCacheDiskConverter(new GsonDiskConverter())//默認(rèn)緩存使用序列化轉(zhuǎn)化
.setCacheMaxSize(50 * 1024 * 1024);//設(shè)置緩存大小為50M
(2)在進(jìn)行請求的時候,設(shè)置緩存模式和緩存的key即可摔蓝。如下:
XHttp.get("/book/getAllBook")
.timeOut(10 * 1000)//測試局部超時10s
.cacheMode(mCacheMode)
.cacheKey(CACHE_KEY)//緩存key
.retryCount(5)//重試次數(shù)
.cacheTime(5 * 60)//緩存時間300s赂苗,默認(rèn)-1永久緩存 okhttp和自定義緩存都起作用
.cacheDiskConverter(new GsonDiskConverter())//默認(rèn)使用的是 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 = "我來自遠(yuǎn)程網(wǎng)絡(luò)";
}
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.** { *; }