cacheResult) {
HttpLog.i(cacheResult.toString());
String from = "";
if (cacheResult.isFromCache) {
from = "我来自缓存";
} else {
from = "我来自远程网络";
}
....
}
});
```
### 移除缓存
支持根据缓存key移除缓存,主要是针对RxCache才能起作用
```
EasyHttp.removeCache("cachekey");
```
### 清空缓存
```
EasyHttp.clearCache();
```
### RxCache
RxCache是自己封装的一个本地缓存功能库,采用Rxjava+DiskLruCache来实现,线程安全内部采用ReadWriteLock机制防止频繁读写缓存造成的异常,可以独立使用,单独用RxCache来存储数据。采用transformer与网络请求结合,可以实现网络缓存功能,本地硬缓存,具有缓存读写功能(异步)、缓存是否存在、根据key删除缓存、清空缓存(异步)、缓存Key会自动进行MD5加密、可以设置缓存磁盘大小、缓存key、缓存时间、缓存存储的转换器、缓存目录、缓存Version等功能本库不作为重点介绍。后期会将此代码独立开源一个库,作为一分钟让你自己的网络库也具有缓存功能,敬请期待!!!
## 动态参数
动态参数就是像我们的token、时间戳timeStamp、签名sign等,这些参数不能是全局参数因为是变化的,设置成局部参数又太麻烦,每次都要获取。token是有有效时间的或者异地登录等都会变化重新获取,时间戳一般是根据系统的时间,sign是根据请求的url和参数进行加密签名一般都有自己的签名规则。有的接口需要这些参数有的接口不需要,本库很好的解决这个问题。
#### 1.在请求的时候可以设置下面三个参数
```
.accessToken(true)//本次请求是否追加token
.timeStamp(false)//本次请求是否携带时间戳
.sign(false)//本次请求是否需要签名
```
#### 2.需要继承库中提供的动态拦截器BaseDynamicInterceptor
继承BaseDynamicInterceptor后就可以获取到参数的设置值,请详细看`CustomSignInterceptor`的注释讲解,也可以查看Demo示例
示例:
```
/**
* 描述:对参数进行签名、添加token、时间戳处理的拦截器
* 主要功能说明:
* 因为参数签名没办法统一,签名的规则不一样,签名加密的方式也不同有MD5、BASE64等等,只提供自己能够扩展的能力。
* 作者: zhouyou
* 日期: 2017/5/4 15:21
* 版本: v1.0
*/
public class CustomSignInterceptor extends BaseDynamicInterceptor {
@Override
public TreeMap dynamic(TreeMap dynamicMap) {
//dynamicMap:是原有的全局参数+局部参数
//你不必关心当前是get/post/上传文件/混合上传等,库中会自动帮你处理。
//根据需要自己处理,如果你只用到token则不必处理isTimeStamp()、isSign()
if (isTimeStamp()) {//是否添加时间戳,因为你的字段key可能不是timestamp,这种动态的自己处理
dynamicMap.put(ComParamContact.Common.TIMESTAMP, String.valueOf(System.currentTimeMillis()));
}
if (isSign()) {是否签名
//1.因为你的字段key可能不是sign,这种需要动态的自己处理
//2.因为你的签名的规则不一样,签名加密方式也不一样,只提供自己能够扩展的能力
dynamicMap.put(ComParamContact.Common.SIGN, sign(dynamicMap));
}
if (isAccessToken()) {//是否添加token
String acccess = TokenManager.getInstance().getAuthModel().getAccessToken();
dynamicMap.put(ComParamContact.Common.ACCESSTOKEN, acccess);
}
//Logc.i("dynamicMap:" + dynamicMap.toString());
return dynamicMap;//dynamicMap:是原有的全局参数+局部参数+新增的动态参数
}
//示例->签名规则:POST+url+参数的拼装+secret
private String sign(TreeMap dynamicMap) {
String url = getHttpUrl().url().toString();
url = url.replaceAll("%2F", "/");
StringBuilder sb = new StringBuilder("POST");
sb.append(url);
for (Map.Entry entry : dynamicMap.entrySet()) {
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
sb.append(AppConstant.APP_SECRET);
HttpLog.i(sb.toString());
return MD5.encode(sb.toString());
}
}
```
#### 3.设置自定义的动态拦截器
最好通过全局的方式设置,因为一般很多接口都会使用到
```
EasyHttp.getInstance()
...
.addInterceptor(new CustomSignInterceptor())//添加动态参数(签名、token、时间戳)拦截器
...
```
## 自定义ApiResult
本库中默认提供的是标准ApiResult.内部是靠ApiResult进行解析的,如果你的数据结构跟ApiResult不同,你可以在你的项目中继承ApiResult,然后重写getCode()、getData()、getMsg()和isOk()等方法来实现自己的需求。
本库中ApiResult如下:
```
public class ApiResult {
private int code;
private String msg;
private T data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public boolean isOk() {//请求成功的判断方法
return code == 0 ? true : false;
}
}
```
json格式类似:
```
{
"code": 100010101,
"data": 内容,
"msg": "请求成功"
}
```
假如你的数据结构是这样的:
```
{
"error_code": 0,
"result": 内容,
"reason": "请求成功"
}
```
那么你的basebean可以写成这样
```
public class CustomApiResult extends ApiResult {
String reason;
int error_code;
//int resultcode;
T result;
@Override
public int getCode() {
return error_code;
}
@Override
public void setCode(int code) {
error_code = code;
}
@Override
public String getMsg() {
return reason;
}
@Override
public void setMsg(String msg) {
reason = msg;
}
@Override
public T getData() {
return result;
}
@Override
public void setData(T data) {
result = data;
}
/* @Override
public boolean isOk() {
return error_code==200;//如果不是0表示成功,请重写isOk()方法。
}*/
}
```
那么你的网络请求可以这样写
##### 自定义ApiResult回调方式(通过CallBackProxy代理)
```
EasyHttp.get(url)
.readTimeOut(30 * 1000)//局部定义读超时
.writeTimeOut(30 * 1000)
.connectTimeout(30 * 1000)
//.cacheKey(this.getClass().getSimpleName()+"11")
//.cacheMode(CacheMode.CACHEANDREMOTE)
//.cacheMode(CacheMode.ONLYREMOTE)
//.headers("","")//设置头参数
//.params("name","张三")//设置参数
//.addInterceptor()
//.addConverterFactory()
//.addCookie()
//.timeStamp(true)
.baseUrl("http://apis.juhe.cn")
.params("phone", "手机号")
.params("dtype", "json")
.params("key", "5682c1f44a7f486e40f9720d6c97ffe4")
.execute(new CallBackProxy, ResultBean>(new SimpleCallBack() {
@Override
public void onError(ApiException e) {
//请求错误
}
@Override
public void onSuccess(ResultBean response) {
//请求成功
}
}) {
});
```
这种写法会觉得有点长,CallBackProxy的泛型参数每次都需要填写,其中CustomApiResult是继承ApiResult的,CustomApiResult相当于项目的basebean,对于一个实际项目来讲,basebean是固定的,所以我们可以继续封装这个方法,根据需要一般只需要封装get和post请求就可以了。
```
public static Disposable customExecute(CallBack callBack) {
return execute(new CallBackProxy, T>(callBack) {
});
}
```
通过以上改造,再次调用时直接使用CallBack,不用再关注CallBackProxy,是不是明显简单很多了,具体请看代码Demo!!!
##### 自定义ApiResult订阅方式(通过CallClazzProxy代理)
```
Observable observable = EasyHttp.get("/mobile/get")
.readTimeOut(30 * 1000)//局部定义读超时
.writeTimeOut(30 * 1000)
.baseUrl("http://apis.juhe.cn")
.params("phone", "18688994275")
.params("dtype", "json")
.params("key", "5682c1f44a7f486e40f9720d6c97ffe4")
.execute(new CallClazzProxy, ResultBean>(ResultBean.class) {
});
observable.subscribe(new ProgressSubscriber(this, mProgressDialog) {
@Override
public void onError(ApiException e) {
super.onError(e);
showToast(e.getMessage());
}
@Override
public void onNext(ResultBean result) {
showToast(result.toString());
}
});
```
## 调试模式
一个好的库,一定有比较人性化的调试模式,为了方便开发者查看请求过程和请求日志,本库提供详细的日志打印,最好在开发阶段,请打开调试模式输出优雅的Log.
调试模式的控制在初始化配置时就可以直接设置。
```
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
...
EasyHttp.getInstance()
...
// 打开该调试开关并设置TAG,不需要就不要加入该行
// 最后的true表示是否打印内部异常,一般打开方便调试错误
.debug("EasyHttp", true);
}
}
```
#### Log预览说明
这里一个成功请求的例子:

上方的Log打印了一个Request完整的声明周期,一个请求的Log有以下特点:
1.开头和结尾打了-->http is start和 -->http is Complete分割请求,完整的生命周期的内容都会打印在开头和结尾的里面。
2.request请求和response响应分割,分别是
> -------------------------------request-------------------------------
> -------------------------------response-------------------------------
3.在---request---之后会打印请求的url、当前请求的类型GET/POST... -->GET/POST开头 -->END GET/POST结尾。如果是GET、HEAD请求方式添加的参数将会在这里完整的以url?key=value&key=value的形式打印。
4.在----response----之后会打印(在服务器响应后被打印),包含响应码、响应状态、响应头、cookie,body等以<--200(响应码)开头,<--END HTTP结尾
5.loadCache key=如果设置了缓存,会看到缓存的key,开启了网络缓存功能才会输出。
6.loadCache result=从缓存里读取的结果,开启了网络缓存功能才会输出。
7.save status => true保存缓存的状态
## 混淆
```
#okhttp
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Exceptions
# Retrolambda
-dontwarn java.lang.invoke.*
# 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;
}
###rxandroid-1.2.1
-keepclassmembers class rx.android.**{*;}
# Gson
-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.** { *; }
#RxEasyHttp
-keep class com.zhouyou.http.model.** {*;}
-keep class com.zhouyou.http.cache.model.** {*;}
-keep class com.zhouyou.http.cache.stategy.**{*;}
```
[请查看Demo中完整的混淆文件](https://github.com/zhou-you/RxEasyHttp/blob/master/app/proguard-rules.pro)
## 支持开源
乐于赞赏,感谢朋友们的支持和鼓励,让我们一起努力做一些好东西!
可以使用「微信」「支付宝」客户端赞赏:
