再见,volley。你好square全家桶。
来源:互联网 发布:手机淘宝开店怎么开店 编辑:程序博客网 时间:2024/05/17 21:58
好久没有写博客了,因为前段时间在找工作,最近刚刚算是稍微稳定下来,在工作中我最近在学习百度地图,ArcGIS,OpenCV这些东西的用法,对以前自学的主流Android开发的知识用到的甚少,不过我自己也没有懈怠,在业余时间还是在学习主流的应用开发技术和编写代码。
本篇文章估计是我最后一次写有关Volley的,为什么这么说。主要是因为这个库,随着时间的推移,已经越来越显现出老态。大家可以发现,Volley和Gson这两个Google自家出品的库已经更新的越来越慢,甚至是好久都没有什么重大改动。最明显的一点,也是我今天重点要说的就是对OkHttp的支持问题。
Google官方早就不建议使用HttpClient来完成网络请求,更是在Android 6.0版本中把它彻底从SDK中删除,而另一种方式HttpURLConnection虽然在高版本中没有明显bug,但是它以使用复杂著称,特别的难用。这时候square出品的okhttp则是力压两种原生的Http底层封装API,被众多开发者广泛的接受,不仅如此,据说Android4.4的源码中已经把默认的HttpURLConnection实现换成OkHttp实现了,可见Google官方已经承认了OkHttp的强大的存在。
从上面可以看出来,在2016年,特别是现在,都2016年年底,马上2017了,如果你的应用还没有用上OkHttp,那就真的有点落伍了。同样,如果一个网络封装库,它不支持OkHttp,那这个库就真的该让我们考虑考虑了。
什么?你说Volley支持OkHttp?那你一定是从知乎或者微信公众号过来的。今天我就来具体说明Volley在支持OkHttp的支持性上有多差。
首先,在OkHttp 2.x时代,Volley的确是全面支持OkHttp,你编写一个OkHttpStack类,用它继承Volley的HurlStack类,然后短短几十行代码就可以写出一个OkHttpStack类,如下所示:
package com.icon.app.util;import com.android.volley.toolbox.HurlStack;import com.squareup.okhttp.OkHttpClient;import com.squareup.okhttp.OkUrlFactory;import java.io.IOException;import java.net.HttpURLConnection;import java.net.URL;/** * An {@link com.android.volley.toolbox.HttpStack HttpStack} implementation * which uses OkHttp as its transport. */public class OkHttpStack extends HurlStack { private final OkUrlFactory okUrlFactory; public OkHttpStack() { this(new OkUrlFactory(new OkHttpClient())); } public OkHttpStack(OkUrlFactory okUrlFactory) { if (okUrlFactory == null) { throw new NullPointerException("Client must not be null."); } this.okUrlFactory = okUrlFactory; } @Override protected HttpURLConnection createConnection(URL url) throws IOException { return okUrlFactory.open(url); }}
基本思想就是利用了OkUrlFactory这个类,用它调用open方法并传入url参数可以得到一个HttpURLConnection的对象。
Ok,如果你只想使用OkHttp 2的话,这就可以了,后面也不用继续看了。
但是我想你一定知道OkHttp的最新版本是3.5.0。既然有了最新版,我们就应该使用它,特别是大版本号的更新往往代表着重大升级。但是问题来了,Volley对于okhttp3的支持变得非常牵强!
首先,第一种写法,也就是按照上面的写法,OkUrlFactory被注解成了过时的类,虽然很多情况下过时的API也是可以使用的,但是这个类强行使用就会报错,导致程序崩溃。于是,你说,我们用okhttp-connection 2.x的OkUrlFactory,但OkHttpClient用OkHttp3.x的不就行了吗,但是并不行,因为2和3的包名不一样,2只能和2的配套使用,3只能和3的配套使用。既然不行,那就只能换写法。
于是,我在网上找到了第二种写法:
package com.example.allen.volleymanager.volley;import com.android.volley.AuthFailureError;import com.android.volley.Request;import com.android.volley.toolbox.HttpStack;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.ProtocolVersion;import org.apache.http.StatusLine;import org.apache.http.entity.BasicHttpEntity;import org.apache.http.message.BasicHeader;import org.apache.http.message.BasicHttpResponse;import org.apache.http.message.BasicStatusLine;import java.io.IOException;import java.util.Map;import java.util.concurrent.TimeUnit;import okhttp3.Headers;import okhttp3.MediaType;import okhttp3.OkHttpClient;import okhttp3.Protocol;import okhttp3.RequestBody;import okhttp3.Response;import okhttp3.ResponseBody;/** * Created by Allen Lin on 2016/02/17. */public class OkHttp3Stack implements HttpStack { private final OkHttpClient mClient; public OkHttp3Stack(OkHttpClient client) { this.mClient = client; } private static HttpEntity entityFromOkHttpResponse(Response response) throws IOException { BasicHttpEntity entity = new BasicHttpEntity(); ResponseBody body = response.body(); entity.setContent(body.byteStream()); entity.setContentLength(body.contentLength()); entity.setContentEncoding(response.header("Content-Encoding")); if (body.contentType() != null) { entity.setContentType(body.contentType().type()); } return entity; } @SuppressWarnings("deprecation") private static void setConnectionParametersForRequest (okhttp3.Request.Builder builder, Request<?> request) throws IOException, AuthFailureError { switch (request.getMethod()) { case Request.Method.DEPRECATED_GET_OR_POST: byte[] postBody = request.getPostBody(); if (postBody != null) { builder.post(RequestBody.create (MediaType.parse(request.getPostBodyContentType()), postBody)); } break; case Request.Method.GET: builder.get(); break; case Request.Method.DELETE: builder.delete(); break; case Request.Method.POST: builder.post(createRequestBody(request)); break; case Request.Method.PUT: builder.put(createRequestBody(request)); break; case Request.Method.HEAD: builder.head(); break; case Request.Method.OPTIONS: builder.method("OPTIONS", null); break; case Request.Method.TRACE: builder.method("TRACE", null); break; case Request.Method.PATCH: builder.patch(createRequestBody(request)); break; default: throw new IllegalStateException("Unknown method type."); } } private static RequestBody createRequestBody(Request request) throws AuthFailureError { final byte[] body = request.getBody(); if (body == null) return null; return RequestBody.create(MediaType.parse(request.getBodyContentType()), body); } private static ProtocolVersion parseProtocol(final Protocol protocol) { switch (protocol) { case HTTP_1_0: return new ProtocolVersion("HTTP", 1, 0); case HTTP_1_1: return new ProtocolVersion("HTTP", 1, 1); case SPDY_3: return new ProtocolVersion("SPDY", 3, 1); case HTTP_2: return new ProtocolVersion("HTTP", 2, 0); } throw new IllegalAccessError("Unkwown protocol"); } @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { int timeoutMs = request.getTimeoutMs(); OkHttpClient client = mClient.newBuilder() .readTimeout(timeoutMs, TimeUnit.MILLISECONDS) .connectTimeout(timeoutMs, TimeUnit.MILLISECONDS) .writeTimeout(timeoutMs, TimeUnit.MILLISECONDS) .build(); okhttp3.Request.Builder okHttpRequestBuilder = new okhttp3.Request.Builder(); Map<String, String> headers = request.getHeaders(); for (final String name : headers.keySet()) { okHttpRequestBuilder.addHeader(name, headers.get(name)); } for (final String name : additionalHeaders.keySet()) { okHttpRequestBuilder.addHeader(name, additionalHeaders.get(name)); } setConnectionParametersForRequest(okHttpRequestBuilder, request); okhttp3.Request okhttp3Request = okHttpRequestBuilder.url(request.getUrl()).build(); Response okHttpResponse = client.newCall(okhttp3Request).execute(); StatusLine responseStatus = new BasicStatusLine ( parseProtocol(okHttpResponse.protocol()), okHttpResponse.code(), okHttpResponse.message() ); BasicHttpResponse response = new BasicHttpResponse(responseStatus); response.setEntity(entityFromOkHttpResponse(okHttpResponse)); Headers responseHeaders = okHttpResponse.headers(); for (int i = 0, len = responseHeaders.size(); i < len; i++) { final String name = responseHeaders.name(i), value = responseHeaders.value(i); if (name != null) { response.addHeader(new BasicHeader(name, value)); } } return response; }}
这个写法直接实现HttpStack接口,看起来屌屌的,但是你应该发现了,它使用了大量apache的API,这些API在在Android 6.0版本中都被删除了,根本用不了,于是我想了个办法,把这个类不放在自己的包下,而是放在Volley的包下,于是,编译期确实没有了问题,跑起来以后发送普通的网络请求也是没有问题的,但是,一旦使用volley加载图片就会报NoSuchMehodError这个迷之错误,我花了好长时间也发现不了到底是哪里报出的这个错误,于是又只能放弃这个写法。
再接再厉,第三种写法。这第三种写法,更牛逼,volley不是不支持okhttp吗,我把volley全改了,什么,Volley类,BaseNetwork类,OkHttpStack类等等全是自己写的,他这个严格意义上来说已经不属于对volley的扩展了,而是把它的骨架都换了,但是如果能成功运行倒是可以,可惜的是,他还是使用了apache的API,导致不能用,如果还像上面一样,把它放在volley的包下,我觉得很不爽,因为代码太多,这么多代码放过去,volley都快不是volley了。于是第三种写法也被抛弃。
最后一试,第四种写法,这种写法我也不贴了,它确实没有用apache的API,但是,它用了过时的OkUrlFactory,并且运行起来一样不正常,会报迷之错误。于是这种写法也被抛弃。
最后的最后,我要用okhttp的雄心不死,但是只能退而求其次,用okhttp2,我最终用了2.7.5版本。
综上所属,volley对最新的okhttp的支持非常不友好,如果去看volley的源码,它还对HttpClient保留了支持,并且项目内部大量使用了apache的API,这让人感觉非常不爽。如果我是volley的作者,我早就让HttpClient狗带了。而且之前也说了,从更新频率看,volley的维护已经变的相当不积极,作为一个Google官方出品的库,我不知道现在Google对它的态度如何,但我觉得大致上来看,是相当不乐观的,特别是square全家桶横行天下的现在,在网络请求库中,底层支持且仅支持okhttp的Retrofit独领风骚,我觉得Google没有兴趣非要弄一个可以碾压Retrofit的库才肯罢休,何不花时间做点别人没有做过的事情。
我以前喜欢volley的原因还有一个就是因为它可以简单的加载图片,但是功能实在是太有限了,我以前也写过几篇文章,专门写当volley加载图片遇到功能瓶颈的时候怎么解决。在功能上volley被图片加载四大库完全吊打。
综上所属,volley最终和一些老库一样走向停更是必然的,我不准备再花时间和精力去解决volley的瓶颈,我要向square低头了,我要向Jack Wharton大神低头了,我准备转向Retrofit了,所以,小伙伴们,如果你还在用volley,确实该考虑考虑了。
- 再见,volley。你好square全家桶。
- 你好,再见;你好,幸会!
- 再见,大学!你好,工作!
- 再见,2008!你好,2009!
- 再见2008,你好2009
- 再见北京,你好天津!
- CSDN你好 ,CSDN再见!
- 再见2011,你好,2012。
- 2010再见,你好2011
- 再见,2012,你好,2013.
- 再见,诺基亚.你好,爱立信.
- 再见2013,你好2014
- 再见2014,你好2015
- 2015你好,2014再见!
- 2014再见,2015你好!
- 再见2014,你好2015!
- 2014 你好,再见
- 再见,2014;你好,2015
- 第15周项目3 - B-树的基本操作
- 第15周项目1 -1验证算法
- CentOS6.5 安装 MySQL5.1.71
- 第十六周项目1(5)--验证算法之归并排序
- Ubuntu下SVN客户端——RabbitVCS
- 再见,volley。你好square全家桶。
- 无线通信网络学习之Wlan架构介绍
- 怎么处理警告 xxxxx is missing from working copy
- 第14周项目1-(4)验证平衡二叉排序树相关算法
- 表情识别的简单实现(实时,C++,SVM+Dlib)
- JDK JRE和JVM的区别与联系
- PowerDesigner连接Oracle生成表结构
- 第16周项目1-直接选择排序
- 将友盟分享封装为React Native组件