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
———————————部分核心代码--------------------------------------
[java] view plain copy
1. 1.RequestQueue.start() 启动缓存调度和网络调度
2.
3. public void start() {
4. // Make sure any currently running dispatchers are stopped.
5. // Create the cache dispatcher and start it.
6. new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
7. mCacheDispatcher.start();
8.
9. // Create network dispatchers (and corresponding threads) up to the pool size.
10. for (int i = 0; i < mDispatchers.length; i++) {
11. new NetworkDispatcher(mNetworkQueue, mNetwork,
12. mCache, mDelivery);
13. mDispatchers[i] = networkDispatcher;
14. networkDispatcher.start();
15. }
16. }
[java]
view plain
copy
1. </pre><pre name="code" class="java" style="font-size: 14px;"><pre name="code" class="java">1.BaseNetWork
2. 网络连接任务,@Override
3. public NetworkResponse performRequest(Request<?> request) throws VolleyError {
4. long requestStart = SystemClock.elapsedRealtime();
5. while (true) {
6. null;
7. byte[] responseContents = null;
8. new HashMap<String, String>();
9. try { // Gather headers.
10. new HashMap<String, String>();//请求头信息。
11. //添加本地缓存头信息
12. //发出网络请求
13. StatusLine statusLine = httpResponse.getStatusLine();
14. int statusCode = statusLine.getStatusCode();//HTTP状态码
15. //解析头信息
16. // Handle cache validation.
17. if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//可以使用缓存数据
18. return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
19. true);
20. }
21. // Some responses such as 204s do not have content. We must check.
22. if (httpResponse.getEntity() != null) {//将返回数据 转化为byte数据
23. responseContents = entityToBytes(httpResponse.getEntity());
24. else {//如果没有返回内容。
25. // Add 0 byte response as a way of honestly representing a
26. // no-content request.
27. new byte[0];
28. }
29. // if the request is slow, log it.
30. long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
31. //如果请求时间过长 则打印Log
32. logSlowRequests(requestLifetime, request, responseContents, statusLine);
33.
34. if (statusCode < 200 || statusCode > 299) {//服务器返回异常 则抛出IOException
35. throw new IOException();
36. }
37. return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
38. catch (SocketTimeoutException e) {//链接超时 尝试重新链接 如果达到尝试次数 则会抛出VolleyError异常,此次请求则结束。
39. "socket", request, new TimeoutError());
40. catch (ConnectTimeoutException e) {//链接超时 尝试重新链接 如果达到尝试次数 则会抛出VolleyError异常,此次请求则结束。
41. "connection", request, new TimeoutError());
42. catch (MalformedURLException e) {//Bad URL
43. throw new RuntimeException("Bad URL " + request.getUrl(), e);
44. catch (IOException e) {
45. int statusCode = 0;
46. null;
47. if (httpResponse != null) {
48. statusCode = httpResponse.getStatusLine().getStatusCode();
49. else {//{//如果没有返回httpResponse,就说明没连接
50. throw new NoConnectionError(e);
51. }
52. "Unexpected response code %d for %s", statusCode, request.getUrl());
53. if (responseContents != null) {
54. new NetworkResponse(statusCode, responseContents,responseHeaders, false);
55. if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
56. //认证失败异常,重试
57. "auth",request, new AuthFailureError(networkResponse));
58. else {//服务器异常 // TODO: Only throw ServerError for 5xx status codes.
59. throw new ServerError(networkResponse);
60. }
61. else {//网络异常
62. throw new NetworkError(networkResponse);
63. }
64. }
65. }
66.
1. <span style="font-family: 微软雅黑;">使用Volley加载JSON数据几种方式</span>
1. import java. util.Map ;
2.
3. import org.json.JSONException;
4. import org. json.JSONObject ;
5.
6. import android. app.Activity ;
7. import android. os.Bundle ;
8.
9. import com. android.volley .AuthFailureError;
10. import com. android.volley .Request. Method;
11. import com. android.volley .RequestQueue;
12. import com. android.volley .Response;
13. import com. android.volley .Response. ErrorListener;
14. import com. android.volley .Response. Listener;
15. import com. android.volley .VolleyError;
16. import com.android.volley.toolbox.ImageLoader;
17. import com. android.volley .toolbox. JsonObjectRequest;
18. import com.android.volley.toolbox.JsonRequest;
19. import com. android.volley .toolbox. StringRequest;
20. import com. android.volley .toolbox. Volley;
21. import com. lb.myvolley .R;
22. import com. lb.myvolley .commom. Constants;
23.
24. /***
25. * 加载网络数据( json数据)
26. * **/
27. public class StringMainActivity extends Activity {
28. private RequestQueue queue;
29.
30. @Override
31. protected void onCreate(Bundle savedInstanceState) {
32. super. onCreate(savedInstanceState) ;
33. setContentView(R. layout.activity_main );
34. this );
35. initStringQuest();
36. try {
37. initJSONObject();
38. catch (Exception e) {
39. // TODO Auto-generated catch block
40. e.printStackTrace() ;
41. }
42. }
43.
44. /***
45. * StringQuest的用法 主要就是进行了以下三步操作:
46. *
47. * 1. 创建一个RequestQueue对象。
48. *
49. * 2. 创建一个StringRequest对象。
50. *
51. * 3. 将StringRequest对象添加到RequestQueue里面。
52. * **/
53. private void initStringQuest() {
54. // 第二步
55. new StringRequest( Method.POST ,
56. new Listener<String> () {
57. @Override
58. public void onResponse(String response) {
59. System.out .println(response );
60. }
61. new ErrorListener() {
62. @Override
63. public void onErrorResponse(VolleyError error) {
64. }
65. }) {
66.
67. // 重写getParams()方法,在这里设置POST参数就可以提交给服务器的参数
68. @Override
69. protected Map <String, String> getParams() throws AuthFailureError {
70. new HashMap <String, String>();
71. "params1", "value1");
72. "params2", "value2");
73. return super .getParams() ;
74. }
75. };
76. // 第三部
77. queue.add( request);
78. }
79.
80. /****
81. * . JsonRequest的用法
82. * 类似于StringRequest,JsonRequest也是继承自Request类的,不过由于JsonRequest是一个抽象类
83. * ,因此我们无法直接创建它的实例
84. * ,那么只能从它的子类入手了。JsonRequest有两个直接的子类,JsonObjectRequest和JsonArrayRequest
85. * ,从名字上你应该能就看出它们的区别了吧?一个是用于请求一段JSON数据的,一个是用于请求一段JSON数组的
86. * ********/
87. private void initJSONObject() throws Exception {
88. // JSONObject 用来存放数据提交给服务器
89. new JSONObject() ;
90. "key", "value");
91. new JsonObjectRequest( "", obj,
92. new Listener <JSONObject>() {
93.
94. @Override
95. public void onResponse(JSONObject response) {
96.
97. }
98. new Response .ErrorListener() {
99.
100. @Override
101. public void onErrorResponse(VolleyError error) {
102.
103. }
104. });
105. queue.add( objRequest);
106. }
107.
108. }
使用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的表现就会非常糟糕。
[java] view plain copy
1. import android. app.Activity ;
2. import android. graphics.Bitmap ;
3. import android. graphics.Bitmap .Config;
4. import android. os.Bundle ;
5. import android. widget.ImageView ;
6.
7. import com. android.volley .RequestQueue;
8. import com. android.volley .Response. ErrorListener;
9. import com. android.volley .Response. Listener;
10. import com. android.volley .VolleyError;
11. import com. android.volley .toolbox. ImageLoader;
12. import com. android.volley .toolbox. ImageLoader.ImageListener ;
13. import com. android.volley .toolbox. ImageRequest;
14. import com. android.volley .toolbox. NetworkImageView;
15. import com. android.volley .toolbox. Volley;
16. import com. lb.myvolley .R;
17. import com. lb.myvolley .utils. BitmapCache;
18.
19. /****
20. * 下载图片
21. * *******/
22. public class ImageActivity extends Activity {
23. private RequestQueue queue;
24. private ImageView imgView;
25. private NetworkImageView networkImageView ;
26.
27. @Override
28. protected void onCreate(Bundle savedInstanceState) {
29. super. onCreate(savedInstanceState) ;
30. setContentView(R. layout.activity_image );
31. imgView = (ImageView ) findViewById( R.id .imageView1) ;
32. this );
33. }
34.
35. /**
36. * 使用场景,单张图片 步骤 1. 创建一个RequestQueue对象。
37. *
38. * 2. 创建一个Request对象。
39. *
40. * 3. 将Request对象添加到RequestQueue里面。
41. * **/
42. private void initImageRequestQueue() {
43. /*****
44. * 第一个参数为URL 第二个为Listener <Bitmap>回调 第三第四个参数分别用于指定允许图片最大的宽度和高度
45. * 第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性
46. * 第六个参数是图片请求失败的回调,这里我们当请求失败时在ImageView中显示一张默认图片
47. * */
48. new ImageRequest( "图片地址" , new Listener<Bitmap>() {
49.
50. @Override
51. public void onResponse(Bitmap response) {
52. // 此处设置图片
53. }
54. 300, 300, Config. ARGB_8888, new ErrorListener() {
55.
56. @Override
57. public void onErrorResponse(VolleyError error) {
58.
59. }
60. });
61. queue.add( request);
62. }
63.
64. /*****
65. * 多张图片并可以添加到缓存 步骤 1. 创建一个RequestQueue对象。
66. *
67. * 2. 创建一个ImageLoader对象。
68. *
69. * 3. 获取一个ImageListener对象。
70. *
71. * 4. 调用ImageLoader的get()方法加载网络上的图片。
72. * ***/
73. private void initImageLoader() {
74. new ImageLoader(queue , new BitmapCache());
75. // 第一个参数为imageViewK控件,第二个为默认图片,第三个为失败显示的图片
76. ImageListener listener = ImageLoader.getImageListener (imgView,
77. R.drawable .ic_launcher, R. drawable.ic_launcher );
78. "图片地址" , listener );
79. }
80.
81. /**
82. * 最简单的推荐方式 1. 创建一个RequestQueue对象。
83. *
84. * 2. 创建一个ImageLoader对象。
85. *
86. * 3. 在布局文件中添加一个NetworkImageView控件。 4. 在代码中获取该控件的实例。
87. *
88. * 5. 设置要加载的图片地址。
89. * ***/
90. private void initNetWorkImage() {
91. new ImageLoader(queue , new BitmapCache());
92. networkImageView=( NetworkImageView) findViewById(R. id.network_image_view );
93. //默认显示图片
94. networkImageView.setDefaultImageResId( R.drawable .ic_launcher) ;
95. //失败后显示的图片
96. networkImageView.setErrorImageResId( R.drawable .ic_launcher) ;
97. "https://img-my..net/uploads/201404/13/1397393290_5765.jpeg" ,
98. imageLoader);
99. }
100. }
101.