Volley

Volley简介

Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎在任何项目代码中我们都能看到这两个类的身影,使用率非常高。不过HttpURLConnection和HttpClient的用法还是有些复杂,Android开发团队也是意识到有必要将HTTP通信操作在进行简化,于是在2013年Google I/O大会上退出来一个新的网络通信框架——volley。

Volley处理简单易用之外,在性能方面也进行了大幅度的调整,他的设计目标就是非常适合去进行数据量不大,但通信频繁的网络A座,而对于大数据量的网络操作,比如下载文件,Volley的表现就会非常糟糕。

在使用Volley时,需要导入框架包

jar包的下载地址是:https://code.google.com/p/google-gson/downloads/list

或者

android yuvimage使用 android volley_android yuvimage使用


android yuvimage使用 android volley_android_02

Volley提供的功能

  • JSON,图像等的异步下载
  • 网络请求的排序(scheduling)
  • 网络请求的优先级处理
  • 缓存
  • 多级别取消请求
  • 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)

StringRequest

RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求, 然后按照-定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资
源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
发送一个字符串的请求

RequestQueue queue=null;
public void sendStringRequestClick(View view){
    String url="https://www.baidu.com";
    //创建一个字符串请求 参数(请求方式,URL,响应的回调接口,错误的回调接口)
    StringRequest request=new StringRequest(Request.Method.GET,
            url, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {//正确时的回调方法
            System.out.println(response);
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {//错误时的回调方法
            System.out.println(error);
        }
    });
    queue.add(request);
}

android yuvimage使用 android volley_android_03


注意:一开始运行时url地址是http://www.baidu.com结果回调的是VolleyError的方法,之后改成https就可以了。

发送一个带参数的POST请求

public void sendParansPostStringClick(View view){
    String url = "http://apis.baidu.com/apistore/weatherservice/citylist";
    StringRequest request=new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            System.out.println(response);
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            System.out.println(error);
        }
    }){
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String,String> params=new HashMap<>();
            params.put("cityname","朝阳");
            return params;
        }
    };
    queue.add(request);
}

android yuvimage使用 android volley_android_04


JsonRequest

类似于StringRequest,JsonRequest也是继承自Request类的,JsonRequest是一个抽象类,JsonRequest有两个直接的子类JsonObjectRequest和JsonArrayRequest。
示例

public void sendJsonRequestClick(View view){
    String url="http://ip.taobao.com/service/getIpInfo.php?ip=63.223.108.42&qq-pf-to=pcqq.group";
    //请求参数对象为JSONObject
//        JSONObject jsonObject=new JSONObject();
//        try {
//            jsonObject.put("param","value");
//        } catch (JSONException e) {
//            e.printStackTrace();
//        }
    //参数(请求方式,URL,请求参数,响应的回调接口,错误的回调接口)
    JsonObjectRequest request=new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            System.out.println(response);
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            System.out.println(error);
        }
    });
    queue.add(request);
}

android yuvimage使用 android volley_android yuvimage使用_05

ImageRequest

发送一个ImageRequest

public void sendImageRequestClick(View view){
    String url="http://b.hiphotos.baidu.com/image/pic/item/4b90f603738da977f86d8b56be51f8198618e309.jpg";
            //参数(URL,响应的回调接口,指定图片的宽,指定图片的高(指定为0,不压缩),指定图片颜色属性,错误的回调接口(可以指定显示一张默认的图片))
    ImageRequest request=new ImageRequest(url, new Response.Listener<Bitmap>() {
        @Override
        public void onResponse(Bitmap response) {
            imageView.setImageBitmap(response);
        }
    }, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            System.out.println(error);
        }
    });
    queue.add(request);
}

android yuvimage使用 android volley_android_06

ImageLoader

ImageLoader也可以用于加载网络图片,也是使用ImageRequest来实现的,不过ImageLoader明显比ImageRequest更加高效,因为它不仅可以对图片进行缓存,还可以过滤重复的连接,避免重复发送请求。

使用ImageLoader加载图片
新建一个ImageLoader对象

public void ImageLoaderClick(View view){
        String url="http://b.hiphotos.baidu.com/image/pic/item/4b90f603738da977f86d8b56be51f8198618e309.jpg";
        ImageLoader imageLoader=new ImageLoader(queue, new ImageLoader.ImageCache() {
            //对图片进行缓存
            @Override
            public Bitmap getBitmap(String url) {
                return null;
            }

            @Override
            public void putBitmap(String url, Bitmap bitmap) {

            }
        });
        //获取ImageListener对象
        ImageLoader.ImageListener listener=ImageLoader.getImageListener(imageView,R.mipmap.ic_launcher,R.mipmap.ic_launcher_round);
        imageLoader.get(url,listener,500,500);
    }

android yuvimage使用 android volley_android_07


实现一个带缓存的ImageCache

private class BitmapCache implements ImageLoader.ImageCache {
    private LruCache<String,Bitmap> cache;
    private int maxCache=10*1024;
    public BitmapCache(){
        cache=new LruCache(maxCache);
    }

    @Override
    public Bitmap getBitmap(String url) {
        return cache.get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        cache.put(url,bitmap);
    }
}

修改ImageLoaderClick方法中的一行代码

ImageLoader imageLoader=new ImageLoader(queue, new BitmapCache());

NetworkImageView

布局

<com.android.volley.toolbox.NetworkImageView
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:id="@+id/networkImageView"
        app:layout_constraintTop_toBottomOf="@id/imageView"
        tools:ignore="MissingConstraints" />

通过networkImageView组件加载图片

private void networkImageView() {
        networkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
        networkImageView.setErrorImageResId(R.mipmap.ic_launcher);
        String url="http://b.hiphotos.baidu.com/image/pic/item/4b90f603738da977f86d8b56be51f8198618e309.jpg";
        networkImageView.setImageUrl(url,new ImageLoader(queue,new BitmapCache()));
    }

在onCreate方法中调用

private NetworkImageView networkImageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        networkImageView=findViewById(R.id.networkImageView);
        //创建一个请求队列
        queue= Volley.newRequestQueue(this);
        networkImageView();
    }

当启动程序时,就会显示

android yuvimage使用 android volley_android_08


NetworkImageView在加载图片时会自动获取自身的宽高,然后对比网络图片的宽高,再决定是否需要对图片进行压缩。压缩过程是在内部完全自动化,并不需要我们设置。

自定义XMLRequest

参考https://www.tuicool.com/articles/QbiU3q
新建XMLRequest类,继承Volley的Request:

package com.example.volly;

import android.util.Xml;

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.StringReader;
import java.io.UnsupportedEncodingException;

public class XMLRequest extends Request<XmlPullParser> {
    private final Response.Listener<XmlPullParser> xmlPullParserListener;

    public XMLRequest(int method,String url,Response.Listener<XmlPullParser> xmlPullParserListener, Response.ErrorListener errorListener) {
        super(method,url,errorListener);
        this.xmlPullParserListener = xmlPullParserListener;
    }

    @Override
    protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {
        try {
            String xmlString=new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            XmlPullParser pull= Xml.newPullParser();
            pull.setInput(new StringReader(xmlString));
            return Response.success(pull,HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return Response.error(new ParseError(e));
        } catch (XmlPullParserException e) {
            e.printStackTrace();
            return Response.error(new ParseError(e));
        }
    }

    @Override
    protected void deliverResponse(XmlPullParser response) {
        xmlPullParserListener.onResponse(response);
    }
}

调用方法

XMLRequest xmlRequest = new XMLRequest(Request.Method.GET,
                "http://flash.weather.com.cn/wmaps/xml/china.xml",
                new Response.Listener<XmlPullParser>() {
                    @Override
                    public void onResponse(XmlPullParser response) {
                        try {
                            int eventType = response.getEventType();
                            while (eventType != XmlPullParser.END_DOCUMENT) {
                                switch (eventType) {
                                    case XmlPullParser.START_TAG:
                                        String nodeName = response.getName();
                                        if ("city".equals(nodeName)) {
                                            String pName = new String(response.getAttributeValue(0).getBytes("iso8859-1"), "UTF-8");//解决乱码问题
                                            Log.d("TAG", "pName is " + pName);
                                        }
                                        break;
                                }
                                eventType = response.next();
                            }
                        } catch (XmlPullParserException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("TAG", error.getMessage(), error);
            }
        });
        queue.add(xmlRequest);

android yuvimage使用 android volley_android yuvimage使用_09

自定义GsonRequest

参考https://www.tuicool.com/articles/QbiU3q
新建GsonRequest类,继承Volley的Request:

package com.example.volly;

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;

import java.io.UnsupportedEncodingException;

public class GsonRequest<T> extends Request<T> {
    private final Response.Listener<T> mListener;
    private Gson gson;
    private Class<T> mClass;

    public GsonRequest(int method, String url,Class mclass, Response.Listener<T> mlistener, Response.ErrorListener errorListener) {
        super(method,url,errorListener);
        this.mListener = mlistener;
        this.mClass=mclass;
    }


    @Override
    protected Response parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString=new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(gson.fromJson(jsonString,mClass),HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return Response.error(new ParseError(e));
        }
    }

    @Override
    protected void deliverResponse(T t) {
        mListener.onResponse(t);
    }

}

新建一个Weather类

private WeatherInfo weatherinfo;

public WeatherInfo getWeatherinfo() {
    return weatherinfo;
}

public void setWeatherinfo(WeatherInfo weatherinfo) {
    this.weatherinfo = weatherinfo;
}

接着新建WeatherInfo类

private String city;

private String temp;

private String time;

public String getCity() {
    return city;
}

public void setCity(String city) {
    this.city = city;
}

public String getTemp() {
    return temp;
}

public void setTemp(String temp) {
    this.temp = temp;
}

public String getTime() {
    return time;
}

public void setTime(String time) {
    this.time = time;
}

调用GsonRequest

GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(
        "http://www.weather.com.cn/data/sk/101010100.html", Weather.class,
        new Response.Listener<Weather>() {
            @Override
            public void onResponse(Weather weather) {
                WeatherInfo weatherInfo = weather.getWeatherinfo();
                Log.d("TAG", "city is " + weatherInfo.getCity());
                Log.d("TAG", "temp is " + weatherInfo.getTemp());
                Log.d("TAG", "time is " + weatherInfo.getTime());
            }
        }, new Response.ErrorListener(){
    @Override
    public void onErrorResponse(VolleyError error) {
        Log.e("TAG", error.getMessage(), error);
    }
});
queue.add(gsonRequest);

但是最后的结果显示中文乱码,求解

android yuvimage使用 android volley_android_10

Volley工作流程

android yuvimage使用 android volley_xml_11