Java基础知识强化之网络编程笔记23:Android网络通信之 Volley(Google开源网络通信库)

联合网上资料学习:http://www.open-open.com/lib/view/open1451223702339.html

一、Volley的介绍

1. Volley简介 

  在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,今年的Google I/O 2013上,Volley发布了。Volley是Android平台上的网络通信库能使网络通信更快,更简单,更健壮
这是Volley名称的由来: a burst or emission of many things or a large amount at once
在Google IO的演讲上,其配图是一幅发射火弓箭的图,有点类似流星。见下图:

其实,从这幅图,我们也可以看出来,Volley特别适合数据量不大但是通信频繁的场景

 

 2. Volley的引入背景:

在以前,我们可能面临如下很多麻烦的问题。

(1)比如以前从网上下载图片的步骤可能是这样的流程:

  • 在ListAdapter#getView()里开始图像的读取。
  • 通过AsyncTask等机制使用HttpURLConnection从服务器去的图片资源
  • 在AsyncTask#onPostExecute()里设置相应ImageView的属性。

而在Volley下,只需要一个函数即可,详细见后面的例子。

(2)再比如,屏幕旋转的时候,有时候会导致再次从网络取得数据。为了避免这种不必要的网络访问,我们可能需要自己写很多针对各种情况的处理,比如cache什么的。

(3)再有,比如ListView的时候,我们滚动过快,可能导致有些网络请求返回的时候,早已经滚过了当时的位置,根本没必要显示在list里了,虽然我们可以通过ViewHolder来保持url等来实现防止两次取得,但是那些已经没有必须要的数据,还是会浪费系统的各种资源。

等等……

3.  Volley提供的功能:

简单来说,它提供了如下的便利功能(优势):

   JSON,图像等的异步下载;

  • 网络请求的排序(scheduling)

   网络请求的优先级处理

   缓存

   多级别取消请求

  • 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)

 

二、Volley的使用:

1. 引入Volley非常简单,首先,从git库先克隆一个下来:

1 git clone https://android.googlesource.com/platform/frameworks/volley

然后编译为jar包,再在自己的工程里import进来

注意,这个库要求最低SDK版本为Froyo,即至少要设置android:minSdkVersion为 8 以上。

也可以从Github代码库中获取:https://github.com/mcxiaoke/android-volley

 

我自己也存放了Volley的jar包:http://download.csdn.net/detail/hebao5201314/9581002

2. Volley实现JSON字符串GET请求:

(1)构建一个RequestQueue

1 RequestQueue requestQueue=Volley.newRequestQueue(this);//这里的this指的是Context

(2)创建一个Request

(3)将Request 添加到RequestQueue

注:

在构建JsonObjectRequest对象时,需要四个参数:

个参数代表http方法;

个参数代表访问Url;

个和第参数分别是 响应监听响应错误监听,分别需要覆写onResponse()onErrorResponse()方法;RequestQueue将会执行请求,并将响应回调onResponse()方法,所以需要在onResponse()方法中实现自己的业务逻辑。

 

 

代码如下:

 1 //获取Json字符串
 2     public void getJSONVolley() {
 3          RequestQueue requestQueue = Volley.newRequestQueue(this);
 4          String JSONDateUrl = "http://www.wwtliu.com/jsondata.html";
 5          /**
 6           * JsonObjectRequest(int method, String url, JSONObject jsonRequest, 
 7           *                Listener<JSONObject> listener, ErrorListener errorListener)
 8           */
 9          JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, JSONDateUrl,  null,
10                  new Response.Listener<JSONObject>() {
11 
12                     public void onResponse(JSONObject response) {
13                         System.out.println("response="+response);
14                         
15                     }
16              
17                 }, new Response.ErrorListener() {
18                     public void onErrorResponse(com.android.volley.VolleyError arg0) {
19                         System.out.println("对不起,有问题");
20                     };
21                 }
22             );
23          
24          requestQueue.add(jsonObjectRequest);
25     }

效果如下:

3. Volley实现异步加载图片:

(1)首先开启Apache服务器,在Apache服务器中存放一个图片text.jpg,如下:

 

使用360浏览器访问这个text.jpg文件,结果如下:

 

说明这里的Apache服务器是开启成功,可以正常访问。

 

(2)新建一个Android工程,命名为"MyVolley",如下:

 

(3)我们先看看布局文件activity_main.xml,如下:

这个布局是自适应显示图片的。

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context="com.himi.myvolley.MainActivity" >
10 
11     <ImageView
12         android:id="@+id/iv"
13         android:layout_width="wrap_content"
14         android:layout_height="wrap_content"
15         android:layout_alignParentLeft="true"
16         android:layout_alignParentTop="true"
17         android:layout_marginLeft="30dp"
18         android:layout_marginTop="16dp" />
19 
20 </RelativeLayout>

 

(4)MainActivity.java:

 1 package com.himi.myvolley;
 2 
 3 import org.json.JSONObject;
 4 
 5 import android.app.Activity;
 6 import android.graphics.Bitmap;
 7 import android.os.Bundle;
 8 import android.util.LruCache;
 9 import android.widget.ImageView;
10 
11 import com.android.volley.Request;
12 import com.android.volley.RequestQueue;
13 import com.android.volley.Response;
14 import com.android.volley.toolbox.ImageLoader;
15 import com.android.volley.toolbox.ImageLoader.ImageCache;
16 import com.android.volley.toolbox.ImageLoader.ImageListener;
17 import com.android.volley.toolbox.JsonObjectRequest;
18 import com.android.volley.toolbox.Volley;
19 
20 /**
21  * Volley是Android平台网络通信库:更快,更简单,更健壮。
22  * volley提供的功能:
23  * 1. JSON、图片(异步)
24  * 2. 网络请求的排序
25  * 3. 网络请求的优先级处理
26  * 4. 缓存
27  * 5. 多级别的取消请求
28  * 6. 与Activity生命周期联动(Activity结束时同时取消所有网络请求)
29  *
30  *
31  *    获取Volley()
32  *  git clone https://android.googlesource.com/platform/frameworks/volley
33  */
34 public class MainActivity extends Activity {
35     private ImageView iv1;
36 
37     @Override
38     protected void onCreate(Bundle savedInstanceState) {
39         super.onCreate(savedInstanceState);
40         setContentView(R.layout.activity_main);
41         init();
42         //加载网络图片
43         loadImageVolley();
44     }
45     
46     
47     public void init() {
48         iv1 = (ImageView) findViewById(R.id.iv);
49     }
50 
51     
52     //异步加载图片
53   
54     public void loadImageVolley() {
55         String imageurl = "http://49.123.72.145/text.jpg";
56         RequestQueue requestQueue = Volley.newRequestQueue(this);
57         final LruCache<String, Bitmap> lurcache = new LruCache<String, Bitmap>(20);
58         ImageCache imageCache = new ImageCache() {
59             
60             //返回当前图片
61             public Bitmap getBitmap(String key) {        
62                 return lurcache.get(key);
63             }
64             
65             //缓存图片资源
66             public void putBitmap(String key, Bitmap value) {
67                 lurcache.put(key, value);
68             }
69             
70         };
71         
72         ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
73         /**
74          * getImageListener(ImageView view, int defaultImageResId, int errorImageResId)
75          *
76          */
77         ImageListener listener = imageLoader.getImageListener(iv1, R.drawable.ic_launcher, 
78                  R.drawable.ic_launcher);
79         imageLoader.get(imageurl, listener);
80     }
81 
82 }

这里要使用到网络,所以我们这里在AndroidMainfest.xml添加网络权限,如下:

<uses-permission android:name="android.permission.INTERNET"/>

 

(5)布署程序到模拟器上,如下:

 

4. Volley使用NetWorkImageView:

Volley提供了一个新的控件NetworkImageView来代替传统的ImageView,这个控件的图片属性可以通过:

mImageView.setImageUrl(url, imageLoader)

来设定。而且,这个控件在被从父控件detach的时候,会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题。

(1)这里我们3的项目中展示NetWorkImageView的使用,如下我们首先来到布局文件activity_main.xml,如下:

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context="com.himi.myvolley.MainActivity" >
10 
11     <ImageView
12         android:id="@+id/iv"
13         android:layout_width="wrap_content"
14         android:layout_height="wrap_content"
15         android:layout_alignParentLeft="true"
16         android:layout_alignParentTop="true"
17         android:layout_marginLeft="30dp"
18         android:layout_marginTop="16dp" />
19 
20     <com.android.volley.toolbox.NetworkImageView
21         android:id="@+id/imageView1"
22         android:layout_width="wrap_content"
23         android:layout_height="wrap_content"
24         android:layout_centerHorizontal="true"
25         android:layout_centerVertical="true"
26          />
27 
28 </RelativeLayout>

(2)然后是MainActivity.java,如下:

  1 package com.himi.myvolley;
  2 
  3 import org.json.JSONObject;
  4 
  5 import android.app.Activity;
  6 import android.graphics.Bitmap;
  7 import android.os.Bundle;
  8 import android.util.LruCache;
  9 import android.widget.ImageView;
 10 
 11 import com.android.volley.Request;
 12 import com.android.volley.RequestQueue;
 13 import com.android.volley.Response;
 14 import com.android.volley.toolbox.ImageLoader;
 15 import com.android.volley.toolbox.ImageLoader.ImageCache;
 16 import com.android.volley.toolbox.ImageLoader.ImageListener;
 17 import com.android.volley.toolbox.JsonObjectRequest;
 18 import com.android.volley.toolbox.NetworkImageView;
 19 import com.android.volley.toolbox.Volley;
 20 
 21 /**
 22  * Volley是Android平台网络通信库:更快,更简单,更健壮。
 23  * volley提供的功能:
 24  * 1. JSON、图片(异步)
 25  * 2. 网络请求的排序
 26  * 3. 网络请求的优先级处理
 27  * 4. 缓存
 28  * 5. 多级别的取消请求
 29  * 6. 与Activity生命周期联动(Activity结束时同时取消所有网络请求)
 30  *
 31  *
 32  *    获取Volley()
 33  *  git clone https://android.googlesource.com/platform/frameworks/volley
 34  */
 35 public class MainActivity extends Activity {
 36     private ImageView iv1;
 37     private NetworkImageView iv2;
 38 
 39     @Override
 40     protected void onCreate(Bundle savedInstanceState) {
 41         super.onCreate(savedInstanceState);
 42         setContentView(R.layout.activity_main);
 43         init();
 44         //getJSONVolley();
 45         NetWorkImageViewVolley();
 46         
 47     }
 48     
 49     
 50     public void init() {
 51         iv1 = (ImageView) findViewById(R.id.iv);
 52         iv2 = (NetworkImageView) findViewById(R.id.imageView1);
 53         loadImageVolley();
 54     }
 55 
 56     //获取Json字符串
 57     public void getJSONVolley() {
 58          RequestQueue requestQueue = Volley.newRequestQueue(this);
 59          String JSONDateUrl = "http://www.wwtliu.com/jsondata.html";
 60          /**
 61           * JsonObjectRequest(int method, String url, JSONObject jsonRequest, 
 62           *                Listener<JSONObject> listener, ErrorListener errorListener)
 63           */
 64          JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, JSONDateUrl,  null,
 65                  new Response.Listener<JSONObject>() {
 66 
 67                     public void onResponse(JSONObject response) {
 68                         System.out.println("response="+response);
 69                         
 70                     }
 71              
 72                 }, new Response.ErrorListener() {
 73                     public void onErrorResponse(com.android.volley.VolleyError arg0) {
 74                         System.out.println("对不起,有问题");
 75                     };
 76                 }
 77             );
 78          
 79          requestQueue.add(jsonObjectRequest);
 80     }
 81     
 82     //异步加载图片
 83     //http://localhost/lesson-img.png
 84     public void loadImageVolley() {
 85         String imageurl = "http://49.123.72.145/text.jpg";
 86         RequestQueue requestQueue = Volley.newRequestQueue(this);
 87         final LruCache<String, Bitmap> lurcache = new LruCache<String, Bitmap>(20);
 88         ImageCache imageCache = new ImageCache() {
 89             
 90             //返回当前图片
 91             public Bitmap getBitmap(String key) {        
 92                 return lurcache.get(key);
 93             }
 94             
 95             //缓存图片资源
 96             public void putBitmap(String key, Bitmap value) {
 97                 lurcache.put(key, value);
 98             }
 99             
100         };
101         
102         ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
103         /**
104          * getImageListener(ImageView view, int defaultImageResId, int errorImageResId)
105          *
106          */
107         ImageListener listener = imageLoader.getImageListener(iv1, R.drawable.ic_launcher, 
108                  R.drawable.ic_launcher);
109         imageLoader.get(imageurl, listener);
110     }
111     // Volley使用NetWorkImageView
112     public void NetWorkImageViewVolley() {
113         String imageUrl = "http://49.123.72.145/text.jpg";
114         RequestQueue requestQueue = Volley.newRequestQueue(this);
115         final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(20);
116         ImageCache imageCache = new ImageCache() {
117 
118             public Bitmap getBitmap(String key) {
119                 // TODO 自动生成的方法存根
120                 return lruCache.get(key);
121             }
122 
123             public void putBitmap(String key, Bitmap value) {
124                 lruCache.put(key, value);
125                 
126             }
127             
128         };
129         
130         ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
131         iv2.setTag("url");
132         iv2.setImageUrl(imageUrl, imageLoader);
133     }
134 
135 }

其他代码不变,布署程序到模拟器上,效果如下:

 

 

5. Volley的框架原理:

 Volley使用了线程池来作为基础结构,主要分为主线程,cache调度线程和 network调度线程。

主线程 和 cache调度线程 都只有一个,而network调度线程可以有多个,这样能解决比并行问题。如下图:

• 优点:Volley简化了网络通信这块的开发,特别是针对数据量不大但网络通信频繁,对JSON对象,图片加载这两块进行了很好的封装和支持,

• 缺点:对大数据(large payloads ),流媒体,这些case不能很好的支持,还需要使用原始的方法,比如Download Manager等。

 

其中蓝色的是主线程绿色的是缓存线程黄色的是网络线程

(1)当一个Request请求添加到RequestQueue请求队列中,Volley就开始工作了。RequestQueue请求队列中持有一个CacheDispatcher缓存调度器和一组NetworkDispatcher网络调度器。

(2)RequestQueue会先叫来CacheDispatcher缓存调度器,让他去看看,当前请求的数据在不在cache中

     2.1.当前的数据在cache中,那就把数据从cache中取出来,然后经过一番加工,将加工好的数据交付给主线程

     2.2.当前数据没在cache中,进行第3步

(3)进行到了这一步,那肯定是数据没有在缓存中,那只能去网络中获取了,这时候RequestQueue会叫来NetworkDispatcher网络调度器NetworkDispatcher可是有一大帮子呢,其实这是一个线程池,默认情况下会启动4个线程去网络下载数据。所以RequestQueue把当前闲着的NetworkDispatcher叫来,给他们分配任务。

(4)拿到任务的NetworkDispatcher就会去网络上下载数据了,与此同时,他会判断下载到的数据能否写入到cache缓存中,如果可以的话就写入cache,以便于下一次直接从cache中获取到数据。最后,将数据加工,交付给主线程。

 

如果在一个Activity里面启动了网络请求,而在这个网络请求还没返回结果的时候,如果Activity被结束了,则我们需要写如下代码作为防守:

1 @Override 
2 public void onPostExecute(Result r) {  
3     if (getActivity() == null) {  
4         return;  
5     }  
6     // ...  
7 }  

 

Activity被终止之后,如果继续使用其中的Context等,除了无辜的浪费CPU,电池,网络等资源,有可能还会导致程序crash,所以,我们需要处理这种一场情况。

使用Volley的话,我们可以在Activity停止的时候,同时取消所有或部分未完成的网络请求。

Volley里所有的请求结果会返回给主进程,如果在主进程里取消了某些请求,则这些请求将不会被返回给主线程。
比如,可以针对某些个request做取消操作:

1 @Override  
2 public void onStop() {  
3     for (Request <?> req : mInFlightRequests) {  
4         req.cancel();  
5     }  
6     ...  
7 }  

或者,取消这个队列里的所有请求:

1 @Override
2  pubic void onStop() {  
3     mRequestQueue.cancelAll(this);  
4     ...  
5 }  

也可以根据RequestFilter或者Tag来终止某些请求:

1 @Override public void onStop() {  
2     mRequestQueue.cancelAll( new RequestFilter() {})  
3     ...  
4     // or  
5     mRequestQueue.cancelAll(new Object());  
6     ...  

 

posted on 2015-10-19 10:26  鸿钧老祖  阅读(376)  评论(0编辑  收藏  举报

导航