NoHttp是一个开源的Android网络请求封装库,简化了编码中网络请求操作,为URLConnection、OkHttp提供统一访问接口。
一、配置
NoHttp作为一个第三方库,应用的第一步是在App build.gradle中将其添加为依赖,代码如下:
implementation 'com.yanzhenjie.nohttp:nohttp:1.1.11'
NoHttp默认使用URLConnection作为底层网络访问库,以降低App包体大小,如需使用OKHttp作为网络访问库还需添加下面的依赖:
implementation 'com.yanzhenjie.nohttp:okhttp:1.1.11'
另外作为网络封装库,主要功能是访问网络和网络状态进行检测,因此App manife文件需要声明网络权限和网络状态访问权限,代码如下:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
二、初始化
NoHttp提供两个初始化接口:
1、默认初始化
NoHttp.initialize(Context)
NoHttp默认配置中连接、读取超时被设置为10S,使用URLConnection作为底层网络库,以内部存储为缓存路径,并提供SSL Socket工厂、域名校验等默认实现。
2、自定义初始化
NoHttp.initialize(InitializationConfig)
NoHttp以构建者模式实现InitializationConfig实例的创建,通过建造者可以对超时、缓存、cookie、底层网络库、通用头部信息、通用参数、SSL Socket工厂、域名校验器、重试次数等信息进行配置。可以对构建者中的一个或者多个信息进行配置,其中未配置的信息将使用和默认初始化一样的配置。
InitializationConfig实例构建示例如下:
InitializationConfig config = InitializationConfig.newBuilder(context)
.connectionTimeout(30 * 1000) // 设置连接超时
.readTimeout(30 * 1000) // 设置读取超时
.cacheStore( // 设置缓存存储
new DBCacheStore(context).setEnable(true)
)
.cookieStore( // 设置cookie存储路径
new DBCookieStore(context).setEnable(true)
)
.networkExecutor() // 设置底层网络库
.addHeader() // 设置通用头部信息,所有请求都会携带这里设置的头部信息
.addParam() // 设置通用参数,所有请求都会携带这里设置的请求参数
.sslSocketFactory() // 设置SSL Socket工厂
.hostnameVerifier() // 设置域名校验器
.retry(x) // 设置重试次数
.build(); // 根据配置生成InitializationConfig实例
三、日志输出
NoHttp默认不输出任何信息,如需查看请求和响应相关信息,可通过下面接口打开信息输出开关。
Logger.setDebug(true);// 开启信息输出开关, 配置后可看到请求过程、日志和错误信息。
Logger.setTag("NoHttpSample");// 设置打印信息的tag。
四、同步请求和异步请求
NoHttp中请求最终都是通过执行器执行,执行器分为同步执行器和异步执行器,下面分别演示两种执行器的使用。
同步执行器:
StringRequest req = new StringRequest("http://api.nohttp.net", RequestMethod.POST);
Response<String> response = SyncRequestExecutor.INSTANCE.execute(req);
if (response.isSucceed()) {// 请求成功,获取请求结果
String result = response.get();
} else {// 请求失败,获取请求异常
Exception e = response.getException();
}
基于线程池的异步执行器:
StringRequest request = new StringRequest("http://api.nohttp.net");
Cancelable cancel = AsyncRequestExecutor.INSTANCE.execute(0, request, new SimpleResponseListener<String>() {
@Override
public void onSucceed(int what, Response<String> response) {// 请求成功
}
@Override
public void onFailed(int what, Response<String> response) {// 请求失败
}
});
cancel.cancel();// 如果想取消请求:
boolean isCancelled = cancel.isCancelled();// 判断是否取消:
基于队列的执行器:
1、调用NoHttp接口创建
RequestQueue queue = NoHttp.newRequestQueue(); // 默认三个并发,也可以调用重载版本指定并发数量
...
queue.add(what, request, listener);// 发起请求
...
queue.stop();//关闭队列
2、直接创建RequestQueue实例
RequestQueue queue = new RequestQueue(5);
queue.start(); // 手动启动队列。
...
queue.add(what, request, listener);// 发起请求
...
queue.stop();//关闭队列
队列add()方法中what与listener中what对应,当listener被用于多个请求时用于鉴别请求。
注意队列是可重复利用的资源,频繁的创建销毁队列会带来额外的性能消耗。
五、封装转换
NoHttp对常见的数据格式做了封装转换,如下所示:
StringRequest request = new StringRequest(url, method);// 请求String
ImageRequest request = new ImageRequest(url, method);// 请求Bitmap
JsonObjectRequest request = new JsonObjectRequest(url, method);// 请求JSONObject
JsonArrayRequest request = new JsonArrayRequest(url, method);// 请求JSONArray
六、拼装URL
NoHttp允许拼装URL,如下所示:
StringRequest request = new StringRequest("http://api.nohttp.net/rest/")
request.path(AppConfig.getUserName())
request.path("userinfo")
七、添加请求头和请求参数
NoHttp通过Request的addHeader()、setHeader()设置请求头信息,示例如下:
StringRequest request = new StringRequest(url, RequestMethod.POST);
.addHeader("name", "yanzhenjie")
.setHeader("sex", "男")//如果已存在将覆盖已经存在的key
NoHttp通过Request的add()、set()设置请求参数,示例如下:
StringRequest request = new StringRequest(url, RequestMethod.POST);
.add("name", "严振杰"
.set("sex", "男")//如果已存在将覆盖已经存在的key
如果参数值为Map类型,Map元素值类型可以是String、File、Binary、List<String>、List<Binary>、List<File>、List<Object>。
八、文件上传
NoHttp上传文件方式有多种,如下所示:
1、表单上传
StringRequest request = ...
request.add("file", new FileBinary(file));
2、每个文件对应一个key多文件上传
StringRequest request = ...
request.add("file1", new FileBinary(File));
request.add("file2", new FileBinary(File));
request.add("file3", new InputStreamBinary(InputStream));
request.add("file4", new ByteArrayBinary(byte[]));
request.add("file5", new BitmapBinary(Bitmap));
3、一个key对应多文件上传
StringRequest request = ...
fileList.add("image", new FileBinary(File));
fileList.add("image", new InputStreamBinary(InputStream));
fileList.add("image", new ByteArrayBinary(byte[]));
fileList.add("image", new BitmapBinary(Bitmap));
4、一个key对应列表多文件上传
StringRequest request = ...;
List<Binary> fileList = ...;
fileList.add(new FileBinary(File));
fileList.add(new InputStreamBinary(InputStream));
fileList.add(new ByteArrayBinary(byte[]));
fileList.add(new BitmapStreamBinary(Bitmap));
request.add("file_list", fileList);
九、请求包体
Http请求无论内容格式为Json
、String
、Xml
、还是Stream,最终都被转换成流提交,所以NoHttp中可以直接指定请求体内容,如下所示:
request.setDefineRequestBody(String, ContentType);// 提交普通字符串
request.setDefineRequestBodyForJson(JsonString)// 提交json字符串
request.setDefineRequestBodyForJson(JSONObject)// 提交jsonObject对象
request.setDefineRequestBodyForXML(XmlString)// 提交xml字符串
request.setDefineRequestBody(InputStream, ContentType)// 提交流
十、缓存策略
NoHttp
支持缓存数据到数据库、SD卡等,并且不论缓存在数据库或者SD,NoHttp
都把数据进行了加密。如需自定义缓存路径,需要在初始化的时候进行配置。
缓存策略设置示例如下:
StringRequest request = new StringRequest(url, method);
request.setCacheMode(CacheMode.DEFAULT);
缓存策略说明:
1、CacheMode.DEFAULT
默认模式 这个模式实现http协议中的内容,比如响应码是304时,当然还会结合E-Tag和LastModify等头。
2、CacheMode.REQUEST_NETWORK_FAILED_READ_CACHE
请求成功返回服务器数据,请求失败则返回本地缓存数据。
3、CacheMode.IF_NONE_CACHE_REQUEST_NETWORK
优先读取本地缓存数据,如果存在本地缓存数据则不再从服务器读取数据
4、CacheMode.ONLY_REQUEST_NETWORK
只从服务器读取数据,不管是否存在本都缓存数据,也不管从服务器读取数据是否失败。
5、CacheMode.ONLY_READ_CACHE
只读取本地缓存数据,即使本地不存在缓存数据也不从服务器读取。
十一、自定义请求
NoHttp中自定义请求需实现继承自RestRequest的子类,自定义过程中需要将最终结果类型指定为泛型参数,并实现parseResponse()
方法将响应体解析成结果类型示例。
自定义请求示例如下:
public class FastJsonRequest extends RestRequestor<JSONObject> {
public FastJsonRequest(String url) {
this(url, RequestMethod.GET);
}
public FastJsonRequest(String url, RequestMethod requestMethod) {
super(url, requestMethod);
}
@Override
public JSONObject parseResponse(Headers header, byte[] body) throws Throwable {
String result = StringRequest.parseResponseString(headers, body);
return JSON.parseObject(result);
}
}
十二、文件下载
文件下载跟请求一样分为同步和异步两种方式,不同的是异步文件下载只支持队列异步。
同步下载:
DownloadRequest request = new DownloadRequest(url, RequestMethod.GET, fileFolder, true, true);
SyncDownloadExecutor.INSTANCE.execute(0, request, new SimpleDownloadListener() {
@Override
public void onStart(int what, boolean resume, long range, Headers headers, long size) {
// 开始下载,回调的时候说明文件开始下载了。
// 参数1:what。
// 参数2:是否是断点续传,从中间开始下载的。
// 参数3:如果是断点续传,这个参数非0,表示之前已经下载的文件大小。
// 参数4:服务器响应头。
// 参数5:文件总大小,可能为0,因为服务器可能不返回文件大小。
}
@Override
public void onProgress(int what, int progress, long fileCount, long speed) {
// 进度发生变化,服务器不返回文件总大小时不回调,因为没法计算进度。
// 参数1:what。
// 参数2:进度,[0-100]。
// 参数3:文件总大小,可能为0,因为服务器可能不返回文件大小。
// 参数4:下载的速度,含义为1S下载的byte大小,计算下载速度时:
// int xKB = (int) speed / 1024; // 单位:xKB/S
// int xM = (int) speed / 1024 / 1024; // 单位:xM/S
}
@Override
public void onFinish(int what, String filePath) {
// 下载完成,参数2为保存在本地的文件路径。
}
});
DownloadRequest有两个构造方法,一个构造方法需手动指定下载文件名;第二个构造方法由NoHttp
根据服务器响应头、URL等自动确定文件名。
注意不管以哪个构造构建下载请求都支持断点续传,如果设置了断点续传,但是文件服务器不支持,NoHttp
先尝试以断点续传请求一次,如果请求失败再以普通下载的方式请求下载。
SimpleDownloadListener是文件下载状态的监听器,是NoHttp提供的DownloadListener
默认实现,DownloadListener
的完整实现示例如下:
private DownloadListener downloadListener = new DownloadListener() {
@Override
public void onStart(int what, boolean resume, long preLenght, Headers header, long count) {
// 下载开始。
}
@Override
public void onProgress(int what, int progress, long downCount, long speed) {
// 更新下载进度和下载网速。
}
@Override
public void onFinish(int what, String filePath) {
// 下载完成。
}
@Override
public void onDownloadError(int what, StatusCode code, CharSequence message) {
// 下载发生错误。
// 参数2:错误类型,是枚举值,每一个枚举的具体请看javaDoc或者demo。
// 参数三:错误信息。
}
@Override
public void onCancel(int what) {
// 下载被取消或者暂停。
}
};
异步下载:
DownloadQueue queue = NoHttp.newDownloadQueue();
...
queue.add(what, request, listener);// 发起下载请求
...
queue.stop();
十三、代码混淆
如果你没有使用Https,NoHttp可以随意混淆,如果使用了Https,请添加如下混淆规则:
-keepclassmembers class ** {
private javax.net.ssl.SSLSocketFactory delegate;
}