Android网络通信框架Volley的学习笔记
作者:云外雁更新于 11月12日访问(277)评论(0)
近期项目需要,着重学习了Android网络通信的几种方法,其中对google今年刚推出的Android平台上的网络通信库Volley非常感兴趣。在这里简单总结一下对Volley的学习,方便日后查阅,也希望能给初次接触的读者一点点帮助。
Volley比较适合在数据量不大但通信频繁的情况,它很好地封装了Android对JSON数据和图片等的请求操作。使用时不再需要像HttpClient、HttpUrlConnection等方法那样,设置一系列的参数,去开启并维护相关线程。我们只需要调用封装好的相应函数,并把请求放到队列里面去就行了。Volley提供了方便的线程管理、图片和JSON数据的请求、请求出错处理等。简单来说,它提供了如下的便利功能:
• JSON,图像等的异步下载;
• 网络请求的排序(scheduling)
• 网络请求的优先级处理
• 缓存
• 多级别取消请求
• 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)
更多关于Volley的介绍,可以参考CSDN的这篇博客。由于Volley是开源的,所以从github clone的library提供的函数可能有点小小的区别,比如说我现在找的两个volley包,只有一个提供了把图片缓存到SD卡的函数。这里只mark一下Volley的基本使用方法,大神请直接忽略我这笔记哈。
Volley里面的所有网络请求有一个基类Request,默认使用UTF-8编码。它是Volley里面最核心的类,不仅完成了各类数据的网络请求,还包揽了返回的response数据和请求错误的处理和分发等工作。它的实现类如下图:
其中:
ClearCacheRequest:
一个虚构的请求(url==null),目的就是为了清空已有的缓存文件
ImageRequest:
这个是向服务器请求图片的类,可以向服务器请求一张图片,返回bitmap.它提供了一个构造函数: public ImageRequest(String url, Response.Listener listener, int maxWidth, int maxHeight,Config decodeConfig, Response.ErrorListener errorListener){}.它可以设置返回的bitmap的最大宽高、bitmap色彩的存储方式。
在Volley里面有三种图片请求方式,ImageRequest、ImageLoader和NetworkImageView。其中ImageRequest是最基本的图片请求类,三种方式最后完成网络图片请求的都是ImageRequest类里面的doParse函数:private Response doParse(NetworkResponse response){...}。
ImageLoader提供了更多更细致的图片请求设置,我们可以实现ImageCache接口,从而可以方便地为图片请求设置缓存。NetworkImageView继承自ImageView类,可以完成图片的请求和最终的显示工作,支持设置请求前和请求失败的默认图片。要想在使用NetworkImageView来请求并显示图片,需要在布局文件里面添加相应的控件,比如下面的demo程序在布局里添加了:
1 2 3 4 5 |
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/netIV_volley"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/linear" />
|
JsonRequest:
从上图可以看出这个类有两个实现类JsonObjectRequest和JsonArrayRequest两个子类,实现对Json对象和数组的请求任务。JsonObjectRequest可以允许上传JsonObject数据,并根据请求返回数据。但JsonArrayRequest的实现过于简单,不能携带上传json数据,只能使用GET方式请求网络。使用起来并不是不方便,需要自己去重写。它仅仅提供了一个构造函数:
1 2 |
public JsonArrayRequest(String url, Listener<JSONArray> listener, ErrorListener errorListener) {
super(Method.GET, url, null, listener, errorListener);}
|
StringRequest:
StringRequest对网络返回的数据处理起来更加灵活,但也存在无法携带字符串进行网络请求的不便(个人觉得)。
干扯了那么多废话,估计看起来费劲,还是来个例子吧:
首先实现ImageCache接口完成一个简单的缓存类,缓存路径为/data/data/包名/cache/volley(ps:有些Volley包里面的Volley.java提供了三个构造函数,支持对缓存路径的设置Volley.newRequestQueueInDisk(Context context, String dir, HttpStack stack))。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import com.android.volley.toolbox.ImageLoader.ImageCache;
/**
* 实现了ImageLoader的ImageCache接口
* @author llb
*/
public class MyImageCache implements ImageCache{
private LruCache<String, Bitmap> cache;
/**
* 构造函数,完成LruCache<String,Bitmap>对象的初始化
* @param maxSize LruCache的最大空间 单位为Byte
*/
public MyImageCache(int maxSize) {
super();
cache=new LruCache<String, Bitmap>(maxSize);
}
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);//在缓存里面寻找是否有
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
//这里传进来的bitmap已经根据请求时候给的maxWidth和maxHeight改变过尺寸了
//如果是NetworkImageView请求的则是默认原尺寸。但有一点一直没整明白:
//为何bitmap的尺寸大小并没有影响到put进去的缓存文件大小呢???
//还望弄明白的哥们提点一下,先谢了(^o^)/
cache.put(url, bitmap);//把图片存进缓存
}
}
|
下面实现对json对象和图片的请求,字符串跟json大同小异,省略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
public class MyVolley extends Activity implements OnClickListener{
private Button bt_json, bt_image, bt_netimage, bt_imageloder;
private ImageView iv_volley;
private TextView tv_volley;
private NetworkImageView netIV_volley;
private String jsonObject="{'name':'llb','age':'20'}";
private JSONObject jsonUp;//要上传的JSONObject
private RequestQueue queue;
private String jsonUrl = "http://218.192.170.251:8080/AndroidServerDemo/LoginServlet";
//上面这个jsonUrl是自己随便写的服务器端,只完成简单的json数据交互
private String imageUrl1 = "http://img1.27.cn/images/201011/04/1288857805_42835600.jpg";
private String imageUrl2 = "http://img.cf8.com.cn/uploadfile/2011/1031/20111031100803979.jpg";
private String imageUrl3 = "http://img.pconline.com.cn/images/upload/upc/tx/wallpaper/1209/07/c1/13698570_1347000164468_320x480.png";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_myvolley);
initView();
}
/**
* 初始化各个控件
*/
private void initView() {
bt_json = (Button) findViewById(R.id.bt_json);
bt_image = (Button) findViewById(R.id.bt_image);
bt_netimage = (Button) findViewById(R.id.bt_netimage);
bt_imageloder = (Button) findViewById(R.id.bt_imageloder);
iv_volley = (ImageView) findViewById(R.id.iv_volley);
tv_volley = (TextView) findViewById(R.id.tv_volley);
netIV_volley = (NetworkImageView) findViewById(R.id.netIV_volley);
queue = Volley.newRequestQueue(this);// 获取一个请求队列对象
bt_json.setOnClickListener(this);//按钮点击事件监听
bt_image.setOnClickListener(this);
bt_netimage.setOnClickListener(this);
bt_imageloder.setOnClickListener(this);
}
/**
* 请求json数据
*/
private void requestJsonObject() {
Log.i("llb", "requestJsonObject()");
try {
jsonUp=new JSONObject(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
Method.POST, jsonUrl,jsonUp, new Listener<JSONObject>() {
@Override
public void onResponse(JSONObject arg0) {
Log.i("llb", "onResponse(JSONObject)");
String json = arg0.toString();
tv_volley.setText("服务器返回的json数据:"+json); }
}, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
Log.i("llb", "onErrorResponse:"+arg0.getMessage());
tv_volley.setText("服务器请求失败:"+arg0.getMessage());
}
});// 也可以在这里携带需要上传的数据
Log.i("llb", "jsonUp"+jsonUp.toString());
queue.add(jsonObjectRequest);// 添加请求到队列里
}
private void requestByImageRequest() {
Log.i("llb", "requestImage()");
// 请求方法1:ImageRequest能够处理单张图片,返回bitmap。
ImageRequest imageRequest = new ImageRequest(imageUrl1,
new Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
Log.i("llb","bitmap height"+response.getHeight()+"&width="+response.getWidth());
iv_volley.setImageBitmap(response);// 显示图片
}
}, 200, 200, Config.ARGB_8888, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MyVolley.this, "请求图片失败了", 0).show();
}
});
// ImageRequest中已经写好了缓存,直接用就好了,使用的是DiskBasedCache
//测试发现直接把大图放到了下面的路径里,上面仅仅是改变了显示时的大小,
//缓存图片大小并无变化,不解??
imageRequest.shouldCache();// 缓存文件在/data/data/包名/cache/volley
queue.add(imageRequest);// 把请求加入到队列里面
}
private void requestByImageLoader() {
// 方法二:利用ImageLoader
ImageListener listener = ImageLoader.getImageListener(iv_volley,
R.drawable.ic_launcher, R.drawable.error);
//缓存文件也放在/data/data/包名/cache/volley,缓存图片大小并无变化
ImageLoader loader = new ImageLoader(queue, new MyImageCache(5 * 1024 * 1024));
loader.get(imageUrl2, listener, 300, 300);// 获取图片
//最后还是调用ImageRequest里面的doParse()函数去请求网络
}
private void requestByNetworkImageView() {
// 方法三:利用NetworkImageView来请求图片
ImageLoader imageLoader = new ImageLoader(queue, new MyImageCache(5 * 1024 * 1024));
netIV_volley.setDefaultImageResId(R.drawable.ic_launcher);//默认图片
netIV_volley.setErrorImageResId(R.drawable.error);//出错时的图片
// public ImageContainer get(String requestUrl, final ImageListener listener) {
// return get(requestUrl, listener, 0, 0);
// }最后事实上调用的是上面这个ImageLoader里面的这个函数,而且是默认尺寸,算是一个缺陷???
netIV_volley.setImageUrl(imageUrl3, imageLoader);//请求图片
}
@Override
public void onClick(View v) { // 按钮响应
switch (v.getId()) {
case R.id.bt_json:// 请求json
requestJsonObject();
break;
case R.id.bt_image:// 利用ImageRequest请求图片
requestByImageRequest();
break;
case R.id.bt_imageloder:// 利用ImageLoader请求图片
requestByImageLoader();
break;
case R.id.bt_netimage:
requestByNetworkImageView();
break;
}
}
}
|
贴几张例子执行结果图:
最后,再次烦请路过的大神帮小弟讲讲,为何bitmap图片的缓存大小总是一样??先谢谢了~~