流行网络库第(一)篇---Volley用法解析

版权声明:本文为LooperJing原创文章,转载请注明出处!

Volley是2013年Google I/O大会上推出了一个新的网络通信框架,特么今年都2016年年尾了,这两年新技术出来的真是多的花了眼睛。虽然是三年前的开原库,但是并不妨碍我们研究它。这一篇先了解其基本用法,下一篇是源码解析,以后的网络库方面的分析,一般也是以这个套路来。


这是一幅经典的图,Volley的中文翻译为“齐射、并发”,这表示,Volley特别适合数据量不大但是通信频繁的场景,不支持 post 大数据,不适合上传文件。本文主要介绍一下Volley的常规用法,就是五个类,StringRequest, JsonRequest ,ImageRequest, ImageLoader, NetWorkImageView

准备工作:
所需要添加的引用库

compile 'com.mcxiaoke.volley:library:1.0.19'

所需要的请求链接

淘宝商品搜索建议:https://suggest.taobao.com/sug?code=utf-8&q=商品名称

所需要的权限

<uses-permission android:name="android.permission.INTERNET" />
一、StringRequest的用法

StringRequest,字面上理解就是String请求,请求的结果是字符串,这个怎么用,先看构造方法。

 /**
  
    /**
     * Creates a new request with the given method.
     *
     * @param method the request {@link Method} to use
     * @param url URL to fetch the string at
     * @param listener Listener to receive the String response
     * @param errorListener Error listener, or null to ignore errors
     */
    public StringRequest(int method, String url, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }

    /**
     * Creates a new GET request.
     *
     * @param url URL to fetch the string at
     * @param listener Listener to receive the String response
     * @param errorListener Error listener, or null to ignore errors
     */
    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }

总共有两个,第一个构造函数有四个参数, 可以指定请求类型,第二个构造函数,有三个参数,默认是GET请求。现在我们尝试发起一个请求,代码就可以这么写。

RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
mQueue.add(getStringRequest());

构建一个消息队列RequestQueue,RequestQueue是什么?下面是RequestQueue的类注释

/**
 * A request dispatch queue with a thread pool of dispatchers.
 *
 * Calling {@link #add(Request)} will enqueue the given Request for dispatch,
 * resolving from either cache or network on a worker thread, and then delivering
 * a parsed response on the main thread.
 */

大概意思就是讲:一个具有线程池的请求调度队列,调用add方法,将会给指定的请求调度,解决从一个工作线程(干活用的线程,即子线程)的缓存或网络,然后提供在主线程上的解析响应。

OK,明确告诉我们需要一个请求,并且add。我们先来个简单的Get请求。

  public StringRequest getStringRequest() {

        return new StringRequest("https://suggest.taobao.com/sug?code=utf-8&q=beizi",

                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {

                        Log.e(getClass().getName(),response);
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.e(getClass().getName(),error.getMessage());
                    }
                }
        );

第一个参数是请求的链接地址,第二个参数是正确的回调,第三个参数是错误回调。
打印结果:

E/test.volley.com.volley.MainActivity$2: {"result":[["杯子","5198589"],["被子","5508160"],["被子冬被","1657880"],["杯子陶瓷","887481"],["杯子 玻璃","964491"],["杯子陶瓷 带盖","360083"],["被子被芯","1835894"],["杯子创意","1946812"],["杯子 保温杯","1615177"],["被子被芯 冬被","1436705"]]}

上面是GET请求,现在使用第一个四个参数的构造函数试一下POST请求,

public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { 
        super(method, url, errorListener); mListener = listener; 
}

构造中竟然不能传递post参数,这怎么搞?不必大惊小怪,基本上所有的网络框架,参数怎么会在构造中传呢。肯定是封装了。看StringRequest的父类Request有不少请求配置相关的方法,其中一个是getParams。

   /**
     * Returns a Map of parameters to be used for a POST or PUT request.  Can throw
     * {@link AuthFailureError} as authentication may be required to provide these values.
     *
     * <p>Note that you can directly override {@link #getBody()} for custom data.</p>
     *
     * @throws AuthFailureError in the event of auth failure
     */
    protected Map<String, String> getParams() throws AuthFailureError {
        return null;
    }

所以,办法有了,在StringRequest中重写父类getParams方法,在getParams中返回我们自己的map。所以上面的Request改成这样

public StringRequest getPostStringRequest() {

        return new StringRequest(Request.Method.POST,"https://suggest.taobao.com/sug?code=utf-8&q=beizi",

                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {

                        Log.e(getClass().getName(),response);
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.e(getClass().getName(),error.getMessage());
                    }
                }
        ){
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> paramMap=new HashMap<>();
                paramMap.put("param1","value1");
                paramMap.put("param2","value3");
                return paramMap;
            }
        };
    }

总结一下步骤:

  • 第一步:构建一个RequestQueue
  • 第二步:构建一个合适的Request
  • 第三步:把第二步的Request add到RequestQueue中
    StringRequest就是这么简单,然而我们更常用的是JsonRequest
二、JsonRequest的用法

废话不多说,直接上代码了。

 private void dispatcherJsonObjectRequest() {

        Volley.newRequestQueue(getApplicationContext()).add(new JsonObjectRequest(Request.Method.POST, "https://suggest.taobao.com/sug?code=utf-8&q=diannao",
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        Log.e(getClass().getName(), response.toString());
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(getClass().getName(), error.getMessage());
            }
        }
        ));

    }

打印结果:

E/test.volley.com.volley.MainActivity$2: {"result":[["电脑桌","3558727"],["电脑椅","1740042"],["电脑包","7051240"],["电脑主机","265635"],["电脑音箱","826213"],["电脑","23633255"],["电脑桌 台式 家用","432711"],["电脑显示器","401223"],["电脑耳机","577117"],["电脑椅家用","366804"]]}

对JsonRequest请求,可以引入GSON等类似的类库将JSON字符串一部解析到位。

三、ImageRequest的用法

ImageRequest 的构造函数如下

  /**
     * Creates a new image request, decoding to a maximum specified width and
     * height. If both width and height are zero, the image will be decoded to
     * its natural size. If one of the two is nonzero, that dimension will be
     * clamped and the other one will be set to preserve the image's aspect
     * ratio. If both width and height are nonzero, the image will be decoded to
     * be fit in the rectangle of dimensions width x height while keeping its
     * aspect ratio.
     *
     * @param url URL of the image
     * @param listener Listener to receive the decoded bitmap
     * @param maxWidth Maximum width to decode this bitmap to, or zero for none
     * @param maxHeight Maximum height to decode this bitmap to, or zero for
     *            none
     * @param scaleType The ImageViews ScaleType used to calculate the needed image size.
     * @param decodeConfig Format to decode the bitmap to
     * @param errorListener Error listener, or null to ignore errors
     */
    public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
            ScaleType scaleType, Config decodeConfig, Response.ErrorListener errorListener) {
        super(Method.GET, url, errorListener); 
        setRetryPolicy(
                new DefaultRetryPolicy(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT));
        mListener = listener;
        mDecodeConfig = decodeConfig;
        mMaxWidth = maxWidth;
        mMaxHeight = maxHeight;
        mScaleType = scaleType;
    }

参数不少,总共有7个,第一个参数就是图片的URL地址,第二个参数是图片请求成功的回调,第三第四个参数分别用于指定允许图片最大的宽度和高度,第五个参数,指定图片的缩放类型,第六个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。第六个参数是图片请求失败的回调,当请求失败时在ImageView中显示一张默认图片。其实个人觉得这不是一种好的设计,参数太多,不利于用户使用。用这个构造函数创建一个新的图像请求,解码到一个最大指定的宽度和高度。如果两个宽度和高度都为零,图像将被解码为其图片本身的大小。如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩。

 private  void dispatherImageRequest(){
        Volley.newRequestQueue(getApplicationContext()).add(new ImageRequest("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png", new Response.Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap response) {
                mImageView.setImageBitmap(response);
            }
        },0,0, ImageView.ScaleType.CENTER, Bitmap.Config.ALPHA_8,new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                mImageView.setImageResource(R.mipmap.ic_launcher);
            }
        }));
    }
四、ImageLoader的用法

ImageLoader的内部也是用ImageRequest来实现,它的构造器可以传入一个ImageCache缓存形参,实现了图片缓存的功能,同时还可以过滤重复链接,避免重复发送请求。


    private void dispatherImageLoader() {
        RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
        ImageLoader imageLoader = new ImageLoader(mQueue, new ImageLoader.ImageCache() {
            int maxSize = 10 * 1024 * 1024;
            private LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(maxSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    return bitmap.getRowBytes() * bitmap.getHeight();
                }
            };
            @Override
            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }

            @Override
            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url,bitmap);
            }
        });
        imageLoader.get("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png", new ImageLoader.ImageListener() {
            @Override
            public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
                mImageView.setImageBitmap(response.getBitmap());
            }

            @Override
            public void onErrorResponse(VolleyError error) {
                mImageView.setImageResource(R.mipmap.ic_launcher);

            }
        });

    }

与ImageRequest实现效果不同的是,ImageLoader加载图片会先显示默认的图片,等待图片加载完成才会显示在ImageView上。

5、NetworkImageView用法

NetworkImageView是一个自定义控件,继承自ImageView,封装了请求网络加载图片的功能。 这种思想不错,在项目中经常可以使用这种思路加强封装性。
Layout中添加

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/networkview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
  RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
        ImageLoader imageLoader = new ImageLoader(mQueue, new ImageLoader.ImageCache() {
            int maxSize = 10 * 1024 * 1024;
            private LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(maxSize) {
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    return bitmap.getRowBytes() * bitmap.getHeight();
                }
            };
            @Override
            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }

            @Override
            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url,bitmap);
            }
        });
        mNetworkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
        mNetworkImageView.setErrorImageResId(R.mipmap.ic_launcher);
        mNetworkImageView.setImageUrl("https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png",imageLoader);

调用mNetworkImageView的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法来分别设置加载中显示的图片,加载失败时显示的图片,以及目标图片的URL地址。和ImageRequest与ImageLoader不同,不需要显示的指定图片的宽高是否要压缩,这是因为,NetworkImageView可以根据我们设置控件的宽和高结合网络图片的宽和高,内部会自动去实现压缩,如果我们不想要压缩可以设置NetworkImageView控件的宽和高都为wrap_content。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容