Android网络通信框架Volley的学习笔记

Android网络通信框架Volley的学习笔记

0

作者:云外雁更新于 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数据和请求错误的处理和分发等工作。它的实现类如下图:
request.jpg
其中:

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;
        }
    }
}

贴几张例子执行结果图:
jieguo.pngjsonerror.png
最后,再次烦请路过的大神帮小弟讲讲,为何bitmap图片的缓存大小总是一样??先谢谢了~~

posted @ 2013-12-20 09:55  笨猪笨笨  阅读(2192)  评论(0编辑  收藏  举报