最近更新了下android studio的版本到1.3.2,API也更新到最新的23,但是在写一个网络请求时遇到了一个问题,那就是HttpClient的API已经完全被擦出了,从此在API23 及以上版本中就不能直接使用HttpClient了,当然如果执意要继续使用,还是有办法的,1.你可以把api降级,这个对于一般人都是无法忍受的,那么还有另一个办法 2.google在sdk里面还给我们留了一个jar包 org.apache.http.legacy.jar,估计也料到有那么一部分极端分子
说到这里,google官方为啥要移除HttpClient呢,原因肯定只有一个,那就是有更好的东西可以替代它,有了新欢,旧爱就不是那么重要了。这个新欢就是Volley框架。
一、为什么是Volley框架呢?
1.避开HttpUrlConnection 和HttpClient
因为HttpUrlConnection 和HttpClient并不是很完美
2.避开AsyncTask框架
自从引入Honeycomb(API 11),系统强制网络操作必须运行在单独的线程中,UI线程之后,每次都还要在另一个线程中处理一些网络的任务,你是不是觉得很是蛋疼
使用AsyncTask,首先你得在onPreExecute做一些准备工作,比如定义context。然后在doInBackground 方法中执行后台任务,最后在onPostExecute中处理结果。这要比实现service更简单直接,因此有大量的例子和文章出现。
但是AsyncTask的主要问题是调用的顺序。你无法决定哪个请求走在最前面,哪个请求必须等待,所有的请求都是按照先进先出的顺序,FIFO。
在某些情况下,问题就出来了,比如当你需要加载一个item中带有图片的列表。当用户向下滚动想获得新的数据时,你无法告诉Activity先加载下一页的json数据,只有慢慢等待上一页的图片加载完。对于像facebook和Twiitter这种item数据的重要性远大于相关图片的应用来说,这会导致严重的用户体验问题。
Volley用其强大的cancellation api解决了这个问题。当调用的时候,你不再需要在onPostExecute中检查Activity是否被销毁。这帮助我们避免了不想要的NullPointerException。
Volley的特点:速度快,可以缓存
在日益提高的用户体验中,速度的要求已经越来越高,特别是针对上网,因为现在的应用基本都会涉及到网络。可以缓存的特点就更不用说了,你有没有想过你有一个item的列表 - 假设是JSON 数组 - 并且每个item都包括一段描述和一个缩略图。现在设想一下用户旋转屏幕之后会发生的事情:activity销毁,列表重新加载,同样的还有图片。长话短说就是:严重的资源浪费以及糟糕的用户体验。
二、Volley的内部框架
Volley分为三层,每一层都工作在自己的线程中。下面是一张简图
在主线程中,你只允许触发请求与处理返回结果,不能多也不能少。
其结果就是你实际上可以忽略在使用AsyncTask的时候doInBackground 方法里面所做的事情。Volley 自动管理http传输同时捕获网络错误,这些都是以前需要我们自己考虑的。
当你向队列中添加了一个请求,背后发生了几件事情。Volley会检查这个请求是否可以从缓存中得到。如果可以,缓存将负责读取,解析,和分发。否则将传递给网络线程。
在网络线程中,一些列的轮询线程不断的在工作。第一个可用的网络线程线程让请求队列出列,发出http请求,解析返回的结果,并写入到缓存中。最后,把解析的结果分发给主线程的listener中。
三、Volley的使用
说了那么多没用的,我们现在进入正题
首先要说一点不太能让人理解的地方,那就是Volley没有官方的Maven repository
第一步、准备好Volley的jar包,如果你电脑上安装有git,那么可以直接用下面的命令来下载Volley的源代码
<span style="font-size:18px;">git clone https://android.googlesource.com/platform/frameworks/volley </span>
如果你想自己导出jar包也行,具体步骤如下:
将源码作为一个module导入。在Android Studio中,在打开项目的情况下,选择File > New Module,然后选择Import Existing Project。选择你下载的源码的所在目录然后确认。一个名为Volley的文件夹将出现在你的项目结构中。Android Studio会自动的更新settings.gradle文件以包含Volley module,因此你只需添加你的依赖compile project(':volley'),然后就完成了。
第二步、使用
不像HttpUrlConnection 和HttpClient那样复杂,一般Volley只会用到两个类,RequestQueue 和Request,你首先创建一个RequestQueue,RequestQueue管理工作线程并将解析的结果发送给主线程。然后你传递一个或者多个Request RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
Volley实现了三种常见的请求类型:
StringRequest
ImageRequest
JsonRequest
从名字中就可以看出每个类各自的作用了,每个类都是继承自Request类,下面给出一个小例子吧
String url = "http://httpbin.org/get?site=code&network=tutsplus"; JsonObjectRequest jsonRequest = new JsonObjectRequest (Request.Method.GET, url, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { // the response is already constructed as a JSONObject! try { response = response.getJSONObject("args"); String site = response.getString("site"), network = response.getString("network"); System.out.println("Site: "+site+"\nNetwork: "+network); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { error.printStackTrace(); } }); Volley.newRequestQueue(this).add(jsonRequest);
对于post请求
String url = "http://httpbin.org/post"; StringRequest postRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { try { JSONObject jsonResponse = new JSONObject(response).getJSONObject("form"); String site = jsonResponse.getString("site"), network = jsonResponse.getString("network"); System.out.println("Site: "+site+"\nNetwork: "+network); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { error.printStackTrace(); } } ) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<>(); // the POST parameters: params.put("site", "code"); params.put("network", "tutsplus"); return params; } }; Volley.newRequestQueue(this).add(postRequest);
@Override protected void onStop() { super.onStop(); mRequestQueue.cancelAll(new RequestQueue.RequestFilter() { @Override public boolean apply(Request<?> request) { // do I have to cancel this? return true; // -> always yes } }); }
这样你就不必担心在onResponse被调用的时候用户已经销毁Activity。这种情况下会抛出NullPointerException异。但是post请求则需要继续,即使用户已经改变了Activity。我们可以通过使用tag来做到,在构造GET请求的时候,添加一个tag给它。
// after declaring your request
request.setTag("GET");
mRequestQueue.add(request);
如果要取消GET请求,只需简单的添加下面的一行代码:
mRequestQueue.cancelAll("GET");
这样你就只会取消GET请求,让其它请求不受影响。注意你必须手动在销毁的Activity中处理这种情况。