是时候用NoHttp来替换Volley了

NoHttp一个有情怀的框架

NoHttpLogo

  我们日常生活中常用的App,包括我们开发者平常的开发中,有90%以上的App都用了Http来和服务器做交互。随着Android6.0开始AndroidSDK中删除了HttpClient的相关的API,我们有必要选择一个可以兼容高低版本系统的Http框架,Google的官方文档中推荐我们使用HttpURLConnection,但是鉴于HttpURLConnection的API过于简单,并且在高低版本系统中有不同的bug,因此开发者如果使用HttpURLConnection封装的话,复杂度和工作量都不少,这就是NoHttp产生的背景。

  NoHttp之所以叫NoHttp,是因为我们使用NoHttp的时候不用管Http协议的东西,NoHttp底层都自动完成了判断,开发者只需要直接调用就好。NoHttp支持傻瓜式调用,支持高级扩展,是一个从小白到大牛都可以使用的Android Http框架。

  NoHttp的底层使用了HttpURLConnection来封装,有人推荐用OkHttp来封装,其实OkHttp对HttpClient和HttpURLConnection都提供了接口,从Android4.4开始HttpURLConnection的底层就是用OkHttp来实现的,现在手机大多数都是4.4以上了吧,尤其国外的更新的更快,其次也没有必要再引进okhttp和okio(okhttp依赖okio)来增大apk的体积。


NoHttp相关链接

NoHttp文档:http://doc.nohttp.net
NoHttp官网:http://www.nohttp.net
NoHttp源码:https://github.com/yanzhenjie/NoHttp

NoHttp简介

  NoHttp是一个Android开源网络框架,实现了RFC2616(Http1.1)协议,一个标准的Http框架。支持普通请求、文件的上传与下载、自动维持Cookie、支持RFC2616规定的所有请求方法(POST、GET、HEAD……)、支持Https(包括访问自签名网站)、支持请求优先级、支持请求与Activity联动、提供了五种缓存策略供开发者选择……

使用方法

  1. compile 'com.yolanda.nohttp:nohttp:1.0.4'

友好的调试模式

  NoHttp提供了调试模式,打开后可以清晰的看到请求过程、怎么传递数据等,基本不用抓包。可以看到请求头、请求数据、响应头、Cookie等的过程。你也不用担心Log太多会让你眼花缭乱,想象不到的整洁。

请求

多文件上传

  所有下载均有进度回调、错误回调等友好的接口。

文件下载

缓存模式

取消请求

  所有取消都支持正在执行的请求。

请求自动维持Cookie

重定向

代理

一. 请求

String请求

  1. // String 请求对象
  2. Request<String> request = NoHttp.createStringRequest(url, requestMethod);

Json请求

  1. // JsonObject
  2. Request<JSONObject> request = NoHttp.createJsonObjectRequest(url, reqeustMethod);
  3. ...
  4. // JsonArray
  5. Request<JSONArray> request = NoHttp.createJsonArrayRequest(url, reqeustMethod);

Bitmap请求

  1. Request<Bitmap> request = NoHttp.createImageRequest(url, requestMethod);

添加参数

  1. Request<JSONObject> request = ...
  2. request.add("name", "yoldada");// String类型
  3. request.add("age", 18);// int类型
  4. request.add("sex", '0')// char类型
  5. request.add("time", 16346468473154); // long类型
  6. ...

添加到队列

  1. RequestQueue requestQueue = NoHttp.newRequestQueue();
  2. // 或者传一个并发值,允许三个请求同时并发
  3. // RequestQueue requestQueue = NoHttp.newRequestQueue(3);
  4. // 发起请求
  5. requestQueue.add(what, request, responseListener);

  上面添加到队列时有一个what,这个what会在responseLisetener响应时回调给开发者,所以我们可以用一个responseLisetener接受多个请求的响应,用what来区分结果。而不用像有的框架一样,每一个请求都要new一个回调。

同步请求

  在当前线程发起请求,在线程这么使用。

  1. Request<String> request = ...
  2. Response<String> response = NoHttp.startRequestSync(request);
  3. if (response.isSucceed()) {
  4. // 请求成功
  5. } else {
  6. // 请求失败
  7. }

二. 文件上传

  支持多文件上传,多个key多个文件,一个key多个文件(List<File>)。支持File、InputStream、ByteArray、Bitmap,实现NoHttp的Binary接口,理论上任何东西都可以传。

单个文件

  1. Request<String> request = ...
  2. request.add("file", new FileBinary(file));

上传多个文件、多个Key多个文件形式

  这里可以添加各种形式的文件,File、Bitmap、InputStream、ByteArray:

  1. Request<String> request = ...
  2. request.add("file1", new FileBinary(File));
  3. request.add("file2", new FileBinary(File));
  4. request.add("file3", new InputStreamBinary(InputStream));
  5. request.add("file4", new ByteArrayBinary(byte[]));
  6. request.add("file5", new BitmapStreamBinary(Bitmap));

上传多个文件、一个Key多个文件形式

  用同一个key添加,如果请求方法是POST、PUT、PATCH、DELETE,同一个key不会被覆盖。

  1. Request<String> request = ...
  2. fileList.add("image", new FileBinary(File));
  3. fileList.add("image", new InputStreamBinary(InputStream));
  4. fileList.add("image", new ByteArrayBinary(byte[]));
  5. fileList.add("image", new BitmapStreamBinary(Bitmap));

  或者:

  1. Request<String> request = ...
  2. List<Binary> fileList = ...
  3. fileList.add(new FileBinary(File));
  4. fileList.add(new InputStreamBinary(InputStream));
  5. fileList.add(new ByteArrayBinary(byte[]));
  6. fileList.add(new BitmapStreamBinary(Bitmap));
  7. request.add("file_list", fileList);

三. 下载文件

  因为下载文件代码比较多,这里贴关键部分,具体的请参考sample。

发起下载请求

  1. //下载文件
  2. downloadRequest = NoHttp.createDownloadRequest...
  3. // what 区分下载
  4. // downloadRequest 下载请求对象
  5. // downloadListener 下载监听
  6. downloadQueue.add(0, downloadRequest, downloadListener);

暂停或者停止下载

  1. downloadRequest.cancel();

监听下载过程

  1. private DownloadListener downloadListener = new DownloadListener() {
  2. @Override
  3. public void onStart(int what, boolean resume, long preLenght, Headers header, long count) {
  4. // 下载开始
  5. }
  6. @Override
  7. public void onProgress(int what, int progress, long downCount) {
  8. // 更新下载进度
  9. }
  10. @Override
  11. public void onFinish(int what, String filePath) {
  12. // 下载完成
  13. }
  14. @Override
  15. public void onDownloadError(int what, StatusCode code, CharSequence message) {
  16. // 下载发生错误
  17. }
  18. @Override
  19. public void onCancel(int what) {
  20. // 下载被取消或者暂停
  21. }
  22. };

四. 缓存模式

1. Http标准协议的缓存,比如响应码是304时

  NoHttp本身是实现了RFC2616,所以这里不用设置或者设置为DEFAULT。

  1. Request<JSONObject> request = NoHttp.createJsonObjectRequest(url);
  2. request.setCacheMode(CacheMode.DEFAULT);

2. 当请求服务器失败的时候,读取缓存

  请求服务器成功则返回服务器数据,如果请求服务器失败,读取缓存数据返回。

  1. Request<JSONObject> request = NoHttp.createJsonObjectRequest(url);
  2. request.setCacheMode(CacheMode.REQUEST_NETWORK_FAILED_READ_CACHE);

3. 如果发现有缓存直接成功,没有缓存才请求服务器

  我们知道ImageLoader的核心除了内存优化外,剩下一个就是发现把内地有图片则直接使用,没有则请求服务器,所以NoHttp这一点非常使用做一个ImageLoader。
  如果没有缓存才去请求服务器,否则使用缓存:

  1. Request<JSONObject> request = NoHttp.createJsonObjectRequest(url);
  2. // 非标准Http协议,改变缓存模式为IF_NONE_CACHE_REQUEST_NETWORK
  3. request.setCacheMode(CacheMode.IF_NONE_CACHE_REQUEST_NETWORK);

  请求图片,缓存图片:

  1. Request<Bitmap> request = NoHttp.createImageRequest(imageUrl);
  2. request.setCacheMode(CacheMode.IF_NONE_CACHE_REQUEST_NETWORK);

4. 仅仅请求网络

  这里不会读取缓存,也不会使用Http304:

  1. Request<Bitmap> request = NoHttp.createImageRequest(imageUrl);
  2. request.setCacheMode(CacheMode.ONLY_REQUEST_NETWORK);
  3. ...

5. 仅仅读取缓存

  如果没有缓存才去请求服务器,否则使用缓存,缓存图片演示:

  1. Request<Bitmap> request = NoHttp.createImageRequest(imageUrl);
  2. request.setCacheMode(CacheMode.ONLY_READ_CACHE);

五. 取消请求

取消单个请求

  直接调用请求对象的cancel方法。

  1. request.cancel();

从队列中取消指定的请求

  给请求set一个sign,取消的时候调用队列的cancelBySign就可以取消掉所有指定这个sign的请求。

  1. request.setCancelSign(sign);
  2. ...
  3. queue.cancelBySign(sign);

取消队列中所有请求

  1. queue.cancelAll();

停止队列

  队列停止后再添加请求到队列后,请求不会被执行。

  1. RequestQueue queue = NoHttp.newRequestQueue();
  2. ...
  3. queue.stop();

六. 自定义请求类型: FastJsonRequest

定义请求对象

  1. public class FastJsonRequest extends RestRequestor<JSONObject> {
  2. public FastJsonRequest(String url) {
  3. super(url);
  4. }
  5. public FastJsonRequest(String url, RequestMethod requestMethod) {
  6. super(url, requestMethod);
  7. }
  8. @Override
  9. public JSONObject parseResponse(String url, Headers headers, byte[] responseBody) {
  10. String result = StringRequest.parseResponseString(url, headers, responseBody);
  11. JSONObject jsonObject = null;
  12. if (!TextUtils.isEmpty(result)) {
  13. jsonObject = JSON.parseObject(result);
  14. } else {
  15. // 这里默认的错误可以定义为你们自己的数据格式
  16. jsonObject = JSON.toJSON("{}");
  17. }
  18. return jsonObject;
  19. }
  20. @Override
  21. public String getAccept() {
  22. // 告诉服务器你接受什么类型的数据
  23. return "application/json";
  24. }
  25. }

b. 使用自定义请求-和NoHttp默认请求没有区别的哦

  1. Request<JSONObject> mRequest = new FastJsonRequest(url, requestMethod);
  2. queue.add(what, mRequest, responseListener);

七. 混淆

需要知道的

NoHttp全部的类都可以混淆。

  NoHttp1.0.0使用了leve23的api,所以打包的时候要用leve23才行。
  NoHttp1.0.1使用了反射调用了高级或者低级的api,所以只要是leve9以上的sdk都可以编译。
  NoHttp1.0.2及以上所有版本同NoHttp1.0.1一样,在NoHttp1.0.1的基础上进行了优化和bug修复。是目前功能最全,最稳定的一个版本,暂时未发现bug。

如果你非要keep

  1. -dontwarn com.yolanda.nohttp.**
  2. -keep class com.yolanda.nohttp.**{*;}

权限

  1. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  3. <uses-permission android:name="android.permission.INTERNET" />
  4. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  5. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />