HttpUtilForAndroid
特点:
第三方隔离:使用过程中不涉及到下一层的库的相关类,全部是
链式调用
不同类型的请求能达到 api 的隔离
底层提供了 okhttp 实现
提供默认-全局-单个请求 三个层次的配置功能
提供 data-code-msg 三个标准字段的 json 解析和回调,并且可自定义配置三个字段
api 设计上结合 http 协议和 android 平台特点来实现:
loading 对话框,实时进度条显示,文件下载后 MD5/SHA1 校验,以及打开/扫描到媒体库,或者选择隐藏下载的图片/视频.
loading 对话框可在任意界面,任意线程弹出.
六种缓存策略可选,涵盖大多数业务场景.
可设置公共参数和公共 headers,并在单个请求中可以选择是否携带这些.
update
回调概览
前处理
onPreValidate(ConfigInfo config)//额外的参数校验,比如 extraTag
onPreExecute()
//成功
onSuccess(T response,String resonseStr,boolean isFromCache)
onSuccessArr(List<T> response, String resonseStr,boolean isFromCache)
onSuccessObj(T response, String responseStr, String data, int code, String msg,boolean isFromCache)
onSuccessArr(List<T> response, String responseStr, String data, int code, String msg,boolean isFromCache)
//失败
onError(String msgCanShow)
onCodeError(String msgCanShow, String hiddenMsg, int code)
onTimeout()//连接超时
onNoNetwork()//没有网络
//业务相关的失败回调
onUnFound()//没有找到对应的内容
onUnlogin()//没有登录或者 token 过期
//请求被取消
onCancel()
//进度
onProgressChange(long transPortedBytes, long totalBytes)
onFilesUploadProgress(long transPortedBytes, long totalBytes,int fileIndex,int filesCount)
//返回为空
onEmpty()
1.在 commonjson 中,返回空,"","{}","[]","null"等情况时会走这个回调
2.或者三字段 json 中,
预期返回为一个 jsonArray(即解析后的 List<T> response),而实际返回"[]"时,会走此回调
全局配置
入口:
HttpUtil.init(getApplicationContext(),"http://www.qxinli.com:9001/api/")
//此方法返回 GlobalConfig 类,此类中所有方法均为链式调用
.xxxx//
GlobalConfig 类的可配置项目
//发送自定义的 userAgent 搞事情
setUserAgent(String userAgent)
//缓存策略
setCacheMode(@CacheStrategy.Mode int cacheMode)
//cookie 管理
setCookieMode(int cookieMode)
//url 前缀
setBaseUrl(String url)
//三字段标准 json
setStandardJsonKeys(String key_data, String key_code, String key_msg)
setStandardJsonCodes(int codeSuccess,int codeUnlogin,int codeUnfound)
//超时时间
setConnectTimeout(int connectTimeout)
setReadTimeout(int readTimeout)
setWriteTimeout(int writeTimeout)
//重试
setRetryCount(int retryCount)
//https
addCrtificateAssert(String fileName)
//打开 log
openLog(String logTag)
//设置公共 header 和公共 params
addCommonHeader(String key,String value)
addCommonParam(String key,String value)
setAppendCommonHeaders(boolean appendCommonHeaders)
setAppendCommonParams(boolean appendCommonParams)
//后续可随时更新这些公共参数
updateCommonHeader(String key,String value)
updateCommonParam(String key,String value)
//自动登录的实现
setTokenInfo(String tokenKey, int tokenLocation)//设置 token 的 key,以及 token 设置在哪里?参数中还是 header 中还是 cookie 中
setLoginManager(LoginManager loginManager)//一个接口,实现带回调的自动登录:autoLogin(MyNetListener listener)
updateToken(String token)//后面实时更新 token 时,调用此 api
几个入口方法
public static <E> StringRequestBuilder<E> requestString(String url)
public static <E> JsonRequestBuilder<E> requestJson(String url, Class clazz)
public static <E> StandardJsonRequestBuilder<E> reqeustStandardJson(String url, Class<E> clazz)
public static <E> DownloadBuilder<E> download(String url)
public static <E> UploadRequestBuilder<E> upload(String url, String fileDesc, String filePath)
单个请求的通用配置
http 方法和回调(链式调用的终点)
getAsync(MyNetListener<T> listener)
postAsync(MyNetListener<T> listener)
url
一般由上方 httpUtil 的初始化时设置以及入口方法传入.
如果入口方法中传入的 url 含有 http 或者 https,则不会拼接初始化设置的 baseUrl.
http 请求参数
两种设置形式
paramsStr(String paramsStr)//将一整个 key=value 形式或者 json 形式的字符串设置进来
addParam(String key,String value)//添加参数键值对
addParams(Map<String,String> params)
setAppendCommonParams(boolean appendCommonParams)//本次请求是否携带公共参数
两种传输形式
post 请求时,在请求体中,可以 key=value&key=value 的形式传输,也可以 json 字符串的形式传输
setParamsAsJson()//默认为 key=value 的形式,调用此方法,改成以 json 形式传输
http 头
addHeader(String key,String value)
addHeaders(Map<String,String> headers)
setAppendCommonHeaders(boolean appendCommonHeaders)//本次请求是否携带公共 headers
缓存控制(todo)
setCacheMode(int cacheMode)
取值有:
CacheStrategy.NO_CACHE = 1;//不使用缓存,该模式下,cacheKey,cacheTime 参数均无效
CacheStrategy.DEFAULT = 2;//完全按照 HTTP 协议的默认缓存规则,例如有 304 响应头时缓存。
CacheStrategy.REQUEST_FAILED_READ_CACHE = 3;//先请求网络,如果请求网络失败,则读取缓存,如果读取缓存失败,本次请求失败。会导致强制缓存响应.
CacheStrategy.IF_NONE_CACHE_REQUEST = 4;//如果缓存不存在才请求网络,否则使用缓存。会导致强制缓存响应
CacheStrategy.FIRST_CACHE_THEN_REQUEST = 5;//先使用缓存,不管是否存在,仍然请求网络。会导致强制缓存响应
注: 分类参考:okhttp-OkGo
cookie 管理
setCookieMode(int cookieMode)
取值有:
- GlobalConfig.COOKIE_NONE 不接收 cookie
- GlobalConfig.COOKIE_MEMORY 会话 cookie,只保存在内存中(默认值)
- GlobalConfig.COOKIE_DISK 持久化 cookie
其他
https
客户端对 https 的处理有很多策略,目前这里实现了两种,第一种是信任所有证书,第二种是读取客户端预置的证书来通信.
setIgnoreCertificateVerify()//设置忽略证书校验
UI: loading 对话框
只要传入相关信息,自动帮开发者弹出,关闭.
能在 dialog 取消时,自动取消对应的网络请求
showLoadingDialog()
showLoadingDialog(String loadingMsg)//内置的 ProgressDialog
showLoadingDialog(Dialog loadingDialog)//传入自定义的 dialog
也可以指定 activity 弹出:
showLoadingDialog(Activity activity)
showLoadingDialog(Activity activity,String loadingMsg)
注意,如果网络请求在 activity 的 onResume 之前发送,那么应该传入 activity 引用,否则会在前一个 activity 里弹出.因为引用是在 onresume 的回调中自动获取的.
内置的 dialog 特点:
outsideCancelable 为 false,cancelable 为 true,也就是点击界面阴影不关闭,点击后退键会关闭
分类请求的配置
普通字符流请求:StringRequestBuilder
构造入口
HttpUtil.buildStringRequest(url)
特殊配置: 无
响应为 json 的请求:
自动解析,并在回调中直接返回解析好的 javabean
HttpUtil.buildJsonRequest("version/latestVersion/v1.json",GetCommonJsonBean.class)
示例:
HttpUtil.buildJsonRequest("version/latestVersion/v1.json",GetCommonJsonBean.class)
.showLoadingDialog(MainActivityNew.this,"加载中...")
.callback(new MyNetListener<GetCommonJsonBean>() {
@Override
public void onSuccess(GetCommonJsonBean response, String resonseStr,boolean isFromCache) {
Logger.json(MyJson.toJsonStr(response));
}
})
.getAsync();
json 的解析说明
如果是 jsonObject,
clazz 传入实体类的 Class,同时 MyNetListener 泛型设置为该实体类
如果 JsonArray,:
clazz 传入数组元素类的 Class,同时 MyNetListener 泛型设置为该实体类,其回调采用
onSuccessArr(List<T> response,String resonseStr)
响应为三字段标准 json 的请求:
根据用户的配置自动解析三个字段,并回调.三个字段和 code 的几个取值单个请求没有设置的话,采用全局中的设置.
json 格式类似:
{
"data":xxx,
"msg":"请求成功!",
"code":0
}
其中,三个字段可以通过 setStandardJsonKey()方法配置,
错误码 code 的几种常见取值(成功,未登录,未找到)也可以配置:setCustomCodeValue()
支持全局配置和单个请求的配置
解析过程为:
服务器返回 json 后,
先根据定义的 code 判断成功还是失败
如果成功,直接将 result 对应的 jsonObject 解析成 GetStandardJsonBean(下面代码)
//返回 json 后,先根据定义的 code 判断成功还是失败,
HttpUtil.buildStandardJsonRequest("http://japi.juhe.cn/joke/content/list.from",GetStandardJsonBean.class)
.addParam("sort","desc")
.addParam("page","1")
.addParam("pagesize","4")
.addParam("time",System.currentTimeMillis()/1000+"")
.addParam("key","fuck you")
.setStandardJsonKey("result","error_code","reason")
.setCustomCodeValue(0,2,-1)
.showLoadingDialog(MainActivityNew.this,"老司机开车了...")
.callback(new MyNetListener<GetStandardJsonBean>() {
@Override
public void onSuccess(GetStandardJsonBean response, String resonseStr,boolean isFromCache) {
Logger.json(MyJson.toJsonStr(response));
}
@Override
public void onError(String error) {
super.onError(error);
Logger.e(error);
}
})
.getAsync();
自定义配置
当 data 对应字段预期为 jsonobject,而实际为空,空字符串,或者"null","{}"时,是走成功的回调还是失败的回调:
全局和单个请求均可配置.默认为 true,走成功的回调
setTreatEmptyDataStrAsSuccess(boolean treatEmptyDataAsSuccess)
三个字段的自定义配置,全局和单个请求均可配置:
setStandardJsonKeys(String key_data, String key_code, String key_msg)
setStandardJsonCodes(int codeSuccess,int codeUnlogin,int codeUnfound)
三字段 json 时,返回错误码为 unlogin 时,实现自动登录,并在登录成功后自动发送前一个请求
- 首先是 GlobalConfig 中配置:
setTokenInfo(String tokenKey, int tokenLocation)//设置 token 的 key,以及 token 设置在哪里?是参数中(0)还是 header 中(1)还是 cookie 中(2).如果是 cookie 中,则 cookie 管理会自动设置成持久化 cookie
setLoginManager(LoginManager loginManager)//一个接口,实现带回调的自动登录:autoLogin(MyNetListener listener)
updateToken(String token)//后面实时更新 token 时,调用此 api
示例:
HttpUtil.init(getApplicationContext(),"http://api.qxinli.com:9005/api/")
.setStandardJsonKeys("data","code","message")
.setStandardJsonCodes(0,5,2)
.setTokenInfo("sessionId",0)
// .addCrtificateRaw(R.raw.srca)
//.addCrtificateAssert("srca.cer")
.openLog("okhttp")
.setLoginManager(new LoginManager() {
@Override
public void autoLogin(@Nullable final MyNetListener listener) {
//注意: 应从 sp 中读取,加密存取,加密传输.这里的 demo 省略了这些安全性措施
login("15989366579965", "123456", new MyNetListener<UserInfo>() {
@Override
public void onSuccess(UserInfo response, String resonseStr, boolean isFromCache) {
GlobalConfig.get().updateToken(response.sessionId);//及时更新 token
if(listener!=null)
listener.onSuccess(response,resonseStr,isFromCache);
}
@Override
public void onError(String msgCanShow) {
super.onError(msgCanShow);
if(listener!=null)
listener.onError(msgCanShow);
}
});
}
});
文件下载
提供的自定义配置有:
文件的保存路径,默认是 download 文件夹下
下载完成后是否校验 md5 或者 sha1,默认不校验,如果校验不成功,则表示下载失败
下载成功后,是否打开文件(不用关系文件类型,内部已经判断,并调用系统 intent 去打开)
下载成功后,是否通知媒体库(比如下载的图片,音视频,想立即让用户可以在系统相册中看到,就需要通知),默认是通知的
下载成功后,是否隐藏该文件,让系统媒体库扫描不到.(通过在文件所在的文件夹下建立一个名为.nomedia 的空文件来实现)
对话框特点:
通过 showLoadingDialog 弹出的自带下载进度显示,无需开发者再操作.
默认是直线进度条
可以选择是圆圈型的还是直线型的,可采用下面的方法配置
showLoadingDialog( String loadingMsg, boolean updateProgress, boolean horizontal)
暂不实现多线程下载,断点续传等功能
示例
HttpUtil.buildDownloadRequest(url2)
.showLoadingDialog(MainActivityNew.this)//显示下载进度 dialog
.savedPath(path)//自定义保存路径
.setOpenAfterSuccess()//下载完成后打开
.setHideFile()//隐藏该文件
.setNotifyMediaCenter(true)//通知媒体库
.verifyMd5("djso8d89dsjd9s7dsfj")//下载完后校验 md5
.getAsync(new MyNetListener() {
@Override
public void onSuccess(Object response, String onSuccess,boolean isFromCache) {
Logger.e("onSuccess:"+onSuccess);
}
@Override
public void onProgressChange(long fileSize, long downloadedSize) {
super.onProgressChange(fileSize, downloadedSize);
Logger.e("progress:"+downloadedSize+"--filesize:"+fileSize);
}
@Override
public void onError(String msgCanShow) {
super.onError(msgCanShow);
Logger.e(msgCanShow);
}
});
文件上传
支持多文件上传的进度回调
暂不实现多线程上传/分片上传/断点续传等高级功能
对话框的进度说明
对于开发者来说,也是带进度的对话框,情况和下载的一样.
示例
HttpUtil.buildUpLoadRequest("http://192.168.1.100:8080/gm/file/q_uploadAndroidApk.do","uploadFile1","/storage/emulated/0/qxinli.apk")//入口方法中至少添加一个文件
.addFile("uploadFile2","/storage/emulated/0/Download/retrofit/qxinli-2.apk")//添加文件的方法
.addParam("uploadFile555","1474363536041.jpg")
.addParam("api_secret777","898767hjk")
.showLoadingDialog(this)
.postAsync(new MyNetListener<String>() {
@Override
public void onSuccess(String response, String resonseStr) {
Logger.e(resonseStr);
}
@Override
public void onError(String error) {
super.onError(error);
Logger.e("error:"+error);
}
@Override
public void onProgressChange(long downloadedSize, long fileSize) {
super.onProgressChange(fileSize, downloadedSize);
Logger.e("upload onProgressChange:"+downloadedSize + " total:"+ fileSize +" progress:"+downloadedSize*100/fileSize);
}
});
请求的取消
请求的取消能够立即关闭 socket,立即回调到 onCancel()中,只要在 activity/fragment 销毁时调用,就可以避免网络请求导致的内存泄漏.
取消单个请求
通过 tag 取消
最佳实践: 在 activity 的 onDestory 方法中取消该 activity 中的相关请求
HttpUtil.cancelRquest(tag);
通过 dialog 取消
如果弹出 dialog,那么不管有没有设置 tag,只要取消 dialog(后退键),就能取消该网络请求.
取消所有请求
HttpUtil.cancleAllRequest()
日志打印效果
默认关闭日志,在 GlobalConfig 的 openLog(String logTag) 打开.
能够将请求和响应的全部内容都打印出来.
如果是上传下载的大数据量,或者 gzip 压缩,则相应的请求体或者响应体不打印.
usage
gradle
Step 1. Add the JitPack repository to your build file
Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
Step 2. Add the dependency
dependencies {
compile 'com.github.hss01248.HttpUtilForAndroid:HttpUtil:Latest release'
}
Latest release: https://github.com/hss01248/HttpUtilForAndroid/releases