1.Volley 简介
-
- 下载地址:https://android.googlesource.com/platform/frameworks/volley
- volley视频:http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded
- 它是谷歌在2013年I/O大会上提出来的一套解决 Android与服务器端进行通信的框架
- 以前我们安卓端与服务器进行通信的时候一般都是使用 AsyncTask, HttpUrlConnection, HttpClient
2.功能介绍
- json,图片等异步下载
- 多级别取消请求
- 和Activity的生命周期的联动(Activity结束,同时取消所有网络请求)
- 网络排序请求
- 网络请求优先级处理
- 缓存
3. volley的使用
3.1从服务器获取数据
java 代码
总结Volley提供了 JsonObjectRequest、 JsonArrayRequest、 StringRequest等 Request形式。
- JsonObjectRequest:返回JSON对象。
- JsonArrayRequest:返回JsonArray。
- StringRequest:返回String,这样可以自己处理数据,更加灵活。
- 另外可以继承Request<T>自定义Request。
3.2 图片加载
- 使用imageRequst下载图片
- 使用imageload下载图片
- 使用NetWorkImageView
4.框架详解
流程: Volley.newRequestQueue(),初始化网络请求队列,然后add()消息到RequestQueue,NetworkDispatcher分发消息到NetWork调用HttpStack请求网络,提交本地缓存信息到请求头,NetWork封装HttpStack返回数据,判断是否使用缓存,或者抛出相关的异常。
相关注释
- Volley 是一个帮助类 主要负责创建请求队列 并且启动队列消息的循环
- HttpStack负责网络解析请求 ,performRequest 返回的是一个Apache的HttpResponse
- 注:在2.3之前的版本,建议使用apache的HttpClient来处理网络请求,在2.3之后的版本建议使用HttpUrlConnection
- NetWork 封装了HttpStack的网络请求,performRequest方法直接返回一个NetWorkResponse 处理了请求异常抛出VolleyError;
- NetWorkDispatcher 网络调度(线程池),分发网络请求到NetWork
———————————部分核心代码--------------------------------------
1.RequestQueue.start() 启动缓存调度和网络调度 public void start() { stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
</pre><pre name="code" class="java" style="font-size: 14px;"><pre name="code" class="java">1.BaseNetWork 网络连接任务,@Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = new HashMap<String, String>(); try { // Gather headers. Map<String, String> headers = new HashMap<String, String>();//请求头信息。 addCacheHeaders(headers, request.getCacheEntry());//添加本地缓存头信息 httpResponse = mHttpStack.performRequest(request, headers);//发出网络请求 StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode();//HTTP状态码 responseHeaders = convertHeaders(httpResponse.getAllHeaders());//解析头信息 // Handle cache validation. if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//可以使用缓存数据 return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true); } // Some responses such as 204s do not have content. We must check. if (httpResponse.getEntity() != null) {//将返回数据 转化为byte数据 responseContents = entityToBytes(httpResponse.getEntity()); } else {//如果没有返回内容。 // Add 0 byte response as a way of honestly representing a // no-content request. responseContents = new byte[0]; } // if the request is slow, log it. long requestLifetime = SystemClock.elapsedRealtime() - requestStart; //如果请求时间过长 则打印Log logSlowRequests(requestLifetime, request, responseContents, statusLine); if (statusCode < 200 || statusCode > 299) {//服务器返回异常 则抛出IOException throw new IOException(); } return new NetworkResponse(statusCode, responseContents, responseHeaders, false); } catch (SocketTimeoutException e) {//链接超时 尝试重新链接 如果达到尝试次数 则会抛出VolleyError异常,此次请求则结束。 attemptRetryOnException("socket", request, new TimeoutError()); } catch (ConnectTimeoutException e) {//链接超时 尝试重新链接 如果达到尝试次数 则会抛出VolleyError异常,此次请求则结束。 attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException e) {//Bad URL throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) { int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { statusCode = httpResponse.getStatusLine().getStatusCode(); } else {//{//如果没有返回httpResponse,就说明没连接 throw new NoConnectionError(e); } VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); if (responseContents != null) { networkResponse = new NetworkResponse(statusCode, responseContents,responseHeaders, false); if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {//认证失败异常,重试 attemptRetryOnException("auth",request, new AuthFailureError(networkResponse)); } else {//服务器异常 // TODO: Only throw ServerError for 5xx status codes. throw new ServerError(networkResponse); } } else {//网络异常 throw new NetworkError(networkResponse); } } }
<span style="font-family: 微软雅黑;">使用Volley加载JSON数据几种方式</span>
import java. util.Map ; import org.json.JSONException; import org. json.JSONObject ; import android. app.Activity ; import android. os.Bundle ; import com. android.volley .AuthFailureError; import com. android.volley .Request. Method; import com. android.volley .RequestQueue; import com. android.volley .Response; import com. android.volley .Response. ErrorListener; import com. android.volley .Response. Listener; import com. android.volley .VolleyError; import com.android.volley.toolbox.ImageLoader; import com. android.volley .toolbox. JsonObjectRequest; import com.android.volley.toolbox.JsonRequest; import com. android.volley .toolbox. StringRequest; import com. android.volley .toolbox. Volley; import com. lb.myvolley .R; import com. lb.myvolley .commom. Constants; /*** * 加载网络数据( json数据) * **/ public class StringMainActivity extends Activity { private RequestQueue queue; @Override protected void onCreate(Bundle savedInstanceState) { super. onCreate(savedInstanceState) ; setContentView(R. layout.activity_main ); queue = Volley. newRequestQueue(StringMainActivity .this ); initStringQuest(); try { initJSONObject(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace() ; } } /*** * StringQuest的用法 主要就是进行了以下三步操作: * * 1. 创建一个RequestQueue对象。 * * 2. 创建一个StringRequest对象。 * * 3. 将StringRequest对象添加到RequestQueue里面。 * **/ private void initStringQuest() { // 第二步 StringRequest request = new StringRequest( Method.POST , Constants.URL_HEAD , new Listener<String> () { @Override public void onResponse(String response) { System.out .println(response ); } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }) { // 重写getParams()方法,在这里设置POST参数就可以提交给服务器的参数 @Override protected Map <String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap <String, String>(); map.put( "params1", "value1"); map.put( "params2", "value2"); return super .getParams() ; } }; // 第三部 queue.add( request); } /**** * . JsonRequest的用法 * 类似于StringRequest,JsonRequest也是继承自Request类的,不过由于JsonRequest是一个抽象类 * ,因此我们无法直接创建它的实例 * ,那么只能从它的子类入手了。JsonRequest有两个直接的子类,JsonObjectRequest和JsonArrayRequest * ,从名字上你应该能就看出它们的区别了吧?一个是用于请求一段JSON数据的,一个是用于请求一段JSON数组的 * ********/ private void initJSONObject() throws Exception { // JSONObject 用来存放数据提交给服务器 JSONObject obj = new JSONObject() ; obj.put( "key", "value"); JsonObjectRequest objRequest = new JsonObjectRequest( "", obj, new Listener <JSONObject>() { @Override public void onResponse(JSONObject response) { } }, new Response .ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); queue.add( objRequest); } }
使用Volley加载网络图片
我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据。Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎在任何项目的代码中我们都能看到这两个类的身影,使用率非常高。
不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码。于是乎,一些Android网络通信框架也就应运而生,比如说AsyncHttpClient,它把HTTP所有的通信细节全部封装在了内部,我们只需要简单调用几行代码就可以完成通信操作了。再比如Universal-Image-Loader,它使得在界面上显示网络图片的操作变得极度简单,开发者不用关心如何从网络上获取图片,也不用关心开启线程、回收图片资源等细节,Universal-Image-Loader已经把一切都做好了。
Android开发团队也是意识到了有必要将HTTP的通信操作再进行简单化,于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。import android. app.Activity ; import android. graphics.Bitmap ; import android. graphics.Bitmap .Config; import android. os.Bundle ; import android. widget.ImageView ; import com. android.volley .RequestQueue; import com. android.volley .Response. ErrorListener; import com. android.volley .Response. Listener; import com. android.volley .VolleyError; import com. android.volley .toolbox. ImageLoader; import com. android.volley .toolbox. ImageLoader.ImageListener ; import com. android.volley .toolbox. ImageRequest; import com. android.volley .toolbox. NetworkImageView; import com. android.volley .toolbox. Volley; import com. lb.myvolley .R; import com. lb.myvolley .utils. BitmapCache; /**** * 下载图片 * *******/ public class ImageActivity extends Activity { private RequestQueue queue; private ImageView imgView; private NetworkImageView networkImageView ; @Override protected void onCreate(Bundle savedInstanceState) { super. onCreate(savedInstanceState) ; setContentView(R. layout.activity_image ); imgView = (ImageView ) findViewById( R.id .imageView1) ; queue = Volley. newRequestQueue(ImageActivity .this ); } /** * 使用场景,单张图片 步骤 1. 创建一个RequestQueue对象。 * * 2. 创建一个Request对象。 * * 3. 将Request对象添加到RequestQueue里面。 * **/ private void initImageRequestQueue() { /***** * 第一个参数为URL 第二个为Listener <Bitmap>回调 第三第四个参数分别用于指定允许图片最大的宽度和高度 * 第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性 * 第六个参数是图片请求失败的回调,这里我们当请求失败时在ImageView中显示一张默认图片 * */ ImageRequest request = new ImageRequest( "图片地址" , new Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { // 此处设置图片 } }, 300, 300, Config. ARGB_8888, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); queue.add( request); } /***** * 多张图片并可以添加到缓存 步骤 1. 创建一个RequestQueue对象。 * * 2. 创建一个ImageLoader对象。 * * 3. 获取一个ImageListener对象。 * * 4. 调用ImageLoader的get()方法加载网络上的图片。 * ***/ private void initImageLoader() { ImageLoader loader = new ImageLoader(queue , new BitmapCache()); // 第一个参数为imageViewK控件,第二个为默认图片,第三个为失败显示的图片 ImageListener listener = ImageLoader.getImageListener (imgView, R.drawable .ic_launcher, R. drawable.ic_launcher ); loader.get( "图片地址" , listener ); } /** * 最简单的推荐方式 1. 创建一个RequestQueue对象。 * * 2. 创建一个ImageLoader对象。 * * 3. 在布局文件中添加一个NetworkImageView控件。 4. 在代码中获取该控件的实例。 * * 5. 设置要加载的图片地址。 * ***/ private void initNetWorkImage() { ImageLoader imageLoader = new ImageLoader(queue , new BitmapCache()); networkImageView=( NetworkImageView) findViewById(R. id.network_image_view ); //默认显示图片 networkImageView.setDefaultImageResId( R.drawable .ic_launcher) ; //失败后显示的图片 networkImageView.setErrorImageResId( R.drawable .ic_launcher) ; networkImageView.setImageUrl( "https://img-my.youkuaiyun.com/uploads/201404/13/1397393290_5765.jpeg" , imageLoader); } }