联合网上资料学习: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库先克隆一个下来:
git clone https://android.googlesource.com/platform/frameworks/volley
然后编译为jar包,再在自己的工程里import进来。
注意,这个库要求最低SDK版本为Froyo,即至少要设置android:minSdkVersion为 以上。
也可以从Github代码库中获取:https://github.com/mcxiaoke/android-volley
我自己也存放了Volley的jar包:http://download.csdn.net/detail/hebao5201314/9581002
2. Volley实现JSON字符串GET请求:
(1)构建一个RequestQueue
RequestQueue requestQueue=Volley.newRequestQueue(this);//这里的this指的是Context
(2)创建一个Request
(3)将Request 添加到RequestQueue
注:
在构建JsonObjectRequest
对象时,需要四个参数:
第一个参数代表http方法;
第二个参数代表访问Url;
第三个和第四个参数分别是 响应监听 和 响应错误监听,分别需要覆写onResponse()和onErrorResponse()方法;RequestQueue
将会执行请求,并将响应回调onResponse()
方法,所以需要在onResponse()方法中实现自己的业务逻辑。
代码如下:
//获取Json字符串
public void getJSONVolley() {
RequestQueue requestQueue = Volley.newRequestQueue(this);
String JSONDateUrl = "http://www.wwtliu.com/jsondata.html";
/**
* JsonObjectRequest(int method, String url, JSONObject jsonRequest,
* Listener<JSONObject> listener, ErrorListener errorListener)
*/
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, JSONDateUrl, null,
new Response.Listener<JSONObject>() { public void onResponse(JSONObject response) {
System.out.println("response="+response); } }, new Response.ErrorListener() {
public void onErrorResponse(com.android.volley.VolleyError arg0) {
System.out.println("对不起,有问题");
};
}
); requestQueue.add(jsonObjectRequest);
}
效果如下:
3. Volley实现异步加载图片:
(1)首先开启Apache服务器,在Apache服务器中存放一个图片text.jpg,如下:
使用360浏览器访问这个text.jpg文件,结果如下:
说明这里的Apache服务器是开启成功,可以正常访问。
(2)新建一个Android工程,命名为"MyVolley",如下:
(3)我们先看看布局文件activity_main.xml,如下:
这个布局是自适应显示图片的。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.himi.myvolley.MainActivity" > <ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="30dp"
android:layout_marginTop="16dp" /> </RelativeLayout>
(4)MainActivity.java:
package com.himi.myvolley; import org.json.JSONObject; import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.LruCache;
import android.widget.ImageView; import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageCache;
import com.android.volley.toolbox.ImageLoader.ImageListener;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley; /**
* Volley是Android平台网络通信库:更快,更简单,更健壮。
* volley提供的功能:
* 1. JSON、图片(异步)
* 2. 网络请求的排序
* 3. 网络请求的优先级处理
* 4. 缓存
* 5. 多级别的取消请求
* 6. 与Activity生命周期联动(Activity结束时同时取消所有网络请求)
*
*
* 获取Volley()
* git clone https://android.googlesource.com/platform/frameworks/volley
*/
public class MainActivity extends Activity {
private ImageView iv1; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
//加载网络图片
loadImageVolley();
} public void init() {
iv1 = (ImageView) findViewById(R.id.iv);
} //异步加载图片 public void loadImageVolley() {
String imageurl = "http://49.123.72.145/text.jpg";
RequestQueue requestQueue = Volley.newRequestQueue(this);
final LruCache<String, Bitmap> lurcache = new LruCache<String, Bitmap>(20);
ImageCache imageCache = new ImageCache() { //返回当前图片
public Bitmap getBitmap(String key) {
return lurcache.get(key);
} //缓存图片资源
public void putBitmap(String key, Bitmap value) {
lurcache.put(key, value);
} }; ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
/**
* getImageListener(ImageView view, int defaultImageResId, int errorImageResId)
*
*/
ImageListener listener = imageLoader.getImageListener(iv1, R.drawable.ic_launcher,
R.drawable.ic_launcher);
imageLoader.get(imageurl, listener);
} }
这里要使用到网络,所以我们这里在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,如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.himi.myvolley.MainActivity" > <ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="30dp"
android:layout_marginTop="16dp" /> <com.android.volley.toolbox.NetworkImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
/> </RelativeLayout>
(2)然后是MainActivity.java,如下:
package com.himi.myvolley; import org.json.JSONObject; import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.LruCache;
import android.widget.ImageView; import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageCache;
import com.android.volley.toolbox.ImageLoader.ImageListener;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.Volley; /**
* Volley是Android平台网络通信库:更快,更简单,更健壮。
* volley提供的功能:
* 1. JSON、图片(异步)
* 2. 网络请求的排序
* 3. 网络请求的优先级处理
* 4. 缓存
* 5. 多级别的取消请求
* 6. 与Activity生命周期联动(Activity结束时同时取消所有网络请求)
*
*
* 获取Volley()
* git clone https://android.googlesource.com/platform/frameworks/volley
*/
public class MainActivity extends Activity {
private ImageView iv1;
private NetworkImageView iv2; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
//getJSONVolley();
NetWorkImageViewVolley(); } public void init() {
iv1 = (ImageView) findViewById(R.id.iv);
iv2 = (NetworkImageView) findViewById(R.id.imageView1);
loadImageVolley();
} //获取Json字符串
public void getJSONVolley() {
RequestQueue requestQueue = Volley.newRequestQueue(this);
String JSONDateUrl = "http://www.wwtliu.com/jsondata.html";
/**
* JsonObjectRequest(int method, String url, JSONObject jsonRequest,
* Listener<JSONObject> listener, ErrorListener errorListener)
*/
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, JSONDateUrl, null,
new Response.Listener<JSONObject>() { public void onResponse(JSONObject response) {
System.out.println("response="+response); } }, new Response.ErrorListener() {
public void onErrorResponse(com.android.volley.VolleyError arg0) {
System.out.println("对不起,有问题");
};
}
); requestQueue.add(jsonObjectRequest);
} //异步加载图片
//http://localhost/lesson-img.png
public void loadImageVolley() {
String imageurl = "http://49.123.72.145/text.jpg";
RequestQueue requestQueue = Volley.newRequestQueue(this);
final LruCache<String, Bitmap> lurcache = new LruCache<String, Bitmap>(20);
ImageCache imageCache = new ImageCache() { //返回当前图片
public Bitmap getBitmap(String key) {
return lurcache.get(key);
} //缓存图片资源
public void putBitmap(String key, Bitmap value) {
lurcache.put(key, value);
} }; ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
/**
* getImageListener(ImageView view, int defaultImageResId, int errorImageResId)
*
*/
ImageListener listener = imageLoader.getImageListener(iv1, R.drawable.ic_launcher,
R.drawable.ic_launcher);
imageLoader.get(imageurl, listener);
}
// Volley使用NetWorkImageView
public void NetWorkImageViewVolley() {
String imageUrl = "http://49.123.72.145/text.jpg";
RequestQueue requestQueue = Volley.newRequestQueue(this);
final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(20);
ImageCache imageCache = new ImageCache() { public Bitmap getBitmap(String key) {
// TODO 自动生成的方法存根
return lruCache.get(key);
} public void putBitmap(String key, Bitmap value) {
lruCache.put(key, value); } }; ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
iv2.setTag("url");
iv2.setImageUrl(imageUrl, imageLoader);
} }
其他代码不变,布署程序到模拟器上,效果如下:
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被结束了,则我们需要写如下代码作为防守:
@Override
public void onPostExecute(Result r) {
if (getActivity() == null) {
return;
}
// ...
}
Activity被终止之后,如果继续使用其中的Context等,除了无辜的浪费CPU,电池,网络等资源,有可能还会导致程序crash,所以,我们需要处理这种一场情况。
使用Volley的话,我们可以在Activity停止的时候,同时取消所有或部分未完成的网络请求。
Volley里所有的请求结果会返回给主进程,如果在主进程里取消了某些请求,则这些请求将不会被返回给主线程。
比如,可以针对某些个request做取消操作:
@Override
public void onStop() {
for (Request <?> req : mInFlightRequests) {
req.cancel();
}
...
}
或者,取消这个队列里的所有请求:
@Override
pubic void onStop() {
mRequestQueue.cancelAll(this);
...
}
也可以根据RequestFilter或者Tag来终止某些请求:
@Override public void onStop() {
mRequestQueue.cancelAll( new RequestFilter() {})
...
// or
mRequestQueue.cancelAll(new Object());
...