一個功能強悍的網絡請求庫,使用RxJava2 + Retrofit2 + OKHttp組合進行封裝。還不趕忙點擊使用說明文檔,體驗一下吧!java
服務端的搭建詳細請點擊查看react
目前支持主流開發工具AndroidStudio的使用,直接配置build.gradle,增長依賴便可.android
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存取規則 |
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();
}
});
複製代碼
在使用它以前,須要下載/定義對應的實體協議,以下:
@RequestParams(url = "/user/addUser", accessToken = false)
public static class UserService_AddUser extends XHttpRequest {
/**
*
*/
public User request;
@Override
protected Boolean getResponseEntityType() {
return null;
}
}
複製代碼
1.註解說明
註解參數 | 類型 | 默認值 | 備註 |
---|---|---|---|
baseUrl | String | "" | 設置該請求的baseUrl |
url | String | "" | 請求網絡接口地址 |
timeout | long | 15000 | 設置超時時間 |
accessToken | boolean | true | 設置是否須要驗證token |
cacheMode | CacheMode | CacheMode.NO_CACHE | 設置請求的緩存模式 |
註解參數 | 類型 | 默認值 | 備註 |
---|---|---|---|
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();
}
});
複製代碼
在使用它以前,須要下載/定義對應的接口協議,以下:
/**
* 訂單
*/
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.註解說明
註解參數 | 類型 | 默認值 | 備註 |
---|---|---|---|
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
。
【注意】請確保網絡請求在主線程中【實質是異步請求(切換到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
實現一個本身的網絡請求日誌攔截器,重寫logForRequest
和logForResponse
兩個方法便可。
(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
,實現isResponseExpired
和responseExpired
方法,以下:
/**
* 判斷是不是失效的響應
*
* @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()); //請求失效校驗攔截器
複製代碼
若是你不想使用默認的ApiResult實體做爲統一的服務端響應實體,好比說你想要下面的響應實體:
private int errorCode; //請求的錯誤碼
private String errorInfo; //請求錯誤的緣由描述
private T result; //請求的結果
private long timeStamp; //服務端返回的時間戳
複製代碼
(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)進行請求的時候使用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接口情有獨鍾,我也提供了相應的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
進行請求,你可使用apiCall
和call
進行請求。
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.** { *; }
複製代碼