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

来源:互联网 发布:中国cctv网络电视 编辑:程序博客网 时间:2024/06/15 08:13

转自:http://my.eoe.cn/bupt/archive/18625.html

推荐:http://www.cnblogs.com/bvin/category/485718.html

         http://www.cr173.com/html/23463_1.html

近期项目需要,着重学习了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程序在布局里添加了:

12345
        <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方式请求网络。使用起来并不是不方便,需要自己去重写。它仅仅提供了一个构造函数:

12
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 9101112131415161718192021222324252627282930
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 99100101102103104105106107108109110111112113114115116117118119120121122123124
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图片的缓存大小总是一样??先谢谢了~~

0 0