现在开发app,可以说离不开网络操作,今天给大家介绍一下android网络框架volley的使用方法。
Volley主页 https://android.googlesource.com/platform/frameworks/volley
Github地址 https://github.com/mcxiaoke/android-volley
Volley:2013年Google I/O大会上推出的一个新的Android网络通信框架,能使网络通信更快,更简单,更健壮。
功能:
Json,图像等的异步下载
网络请求的排序(scheduling)
网络请求的优先级处理
缓存
多级别取消请求
和Activity生命周期联动(Activity结束时同时取消所有请求)
使用volley:
compile 'com.mcxiaoke.volley:library:1.0.19'
StringRequest使用方法:
演示:通过StringRequest发送一个get请求
private void getStringRequest() {
String url="http://api.k780.com:88/?app=phone.get&phone=13800138000&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
RequestQueue queue= Volley.newRequestQueue(this);
StringRequest request=new StringRequest(url, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Log.e("success",s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
queue.add(request);
}
演示:通过StringRequest发送一个post请求
private void postStringRequest() {
String url="http://api.k780.com:88/?app=phone.get";
RequestQueue queue=Volley.newRequestQueue(this);
StringRequest request=new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Log.e("sucess",s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
}){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> map=new HashMap<>();
map.put("phone","13800138000");
map.put("appkey", "10003");
map.put("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4");
map.put("format", "json");
map.put("idcard", "110101199001011114");
return map;
}
};
queue.add(request);
}
通过上述代码,我们可以总结出,StringRequest可以发送get和post请求,但是服务器返回的数据以String类型进行接收。
通过StringRequest发送请求一般需要以下三步:
1.创建一个请求队列RequestQueue
2.创建StringRequest对象
3.将请求对象添加到请求队列中
JsonRequest使用方法:
演示:通过JsonRequest发送一个get请求
private void getJsonRequest() {
String url="http://api.k780.com:88/?app=phone.get&phone=13800138000&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
RequestQueue queue= Volley.newRequestQueue(this);
JsonObjectRequest request=new JsonObjectRequest(url, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
Log.e("success",jsonObject.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
queue.add(request);
}
演示:通过JsonRequest发送一个post请求
private void postJsonRequest() {
String url="http://api.k780.com:88/?app=phone.get";
RequestQueue queue=Volley.newRequestQueue(this);
JsonObjectRequest request=new JsonObjectRequest(Request.Method.POST, url, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
Log.e("success",jsonObject.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
}){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> map=new HashMap<>();
map.put("phone","13800138000");
map.put("appkey", "10003");
map.put("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4");
map.put("format", "json");
map.put("idcard", "110101199001011114");
return map;
}
};
queue.add(request);
}
通过以上分析,可以发现,StringRequest和JsonObjectRequest用法基本一样,只是接收的数据类型不一样。
同理,JsonArrayRequest方法和上面的用法也差不多,这里不做过多介绍。
封装Volley:
具体实现功能如下:
发送get请求
发送post请求
加载网络图片
上传图片
Volley管理的类:
/** * 管理类 * @author Yan */
public class MyVolley {
private static final String TAG="MyVolley";
private static MyVolley instance;
//请求队列
private static RequestQueue mRequestQueue;
//创建ImageLoader
private static ImageLoader mImageLoader;
//默认分配最大空间的几分之几
private final static int RATE=8;
public MyVolley(Context context){
//初始化请求队列(默认创建5个线程)
mRequestQueue=Volley.newRequestQueue(context);
//获取ActivityManager管理者
ActivityManager manager=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
int maxSize=manager.getMemoryClass()/RATE;
//初始化ImageLoader对象
mImageLoader=new ImageLoader(mRequestQueue, new BitmapLruCache(1024*1024*maxSize));
Log.e(TAG, "MyVolley初始化完成");
}
/** * Volley的初始化操作,使用volley前必须调用此方法 */
public static void init(Context context){
if(instance==null){
instance=new MyVolley(context);
}
}
/** * 获取消息队列 */
public static RequestQueue getRequestQueue(){
throwIfNotInit();
return mRequestQueue;
}
/** * 获取ImageLoader */
public static ImageLoader getImageLoader(){
throwIfNotInit();
return mImageLoader;
}
/** * 加入请求队列 */
public static void addRequest(Request<?> request){
getRequestQueue().add(request);
}
/** * 加载网络图片 */
public static void getImage(String requestUrl, ImageView imageView) {
getImage(requestUrl, imageView, 0, 0);
}
/** * 加载网络图片 * */
public static void getImage(String requestUrl, ImageView imageView,
int defaultImageResId, int errorImageResId) {
getImage(requestUrl, imageView, defaultImageResId, errorImageResId, 0,
0);
}
/** * 加载网络图片 * */
public static void getImage(String requestUrl, ImageView imageView,
int defaultImageResId, int errorImageResId, int maxWidth,
int maxHeight) {
imageView.setTag(requestUrl);
try {
getImageLoader().get(
requestUrl,
ImageListenerFactory.getImageListener(imageView,
defaultImageResId, errorImageResId), maxWidth,
maxHeight);
} catch (Exception e) {
e.printStackTrace();
}
}
/** * 检查是否完成初始化 */
private static void throwIfNotInit() {
if (instance == null) {
throw new IllegalStateException("MyVolley尚未初始化,在使用前应该执行init()");
}
}
}
通过以上代码,主要提供了下面几个方法:
1.在构造方法中,初始化一个全局的请求队列RequestQueue,初始化了一个ImageLoader。
2.获取消息队列
3.获取ImageLoader对象
4.将请求加入到消息队列中
5.加载图片
注意:使用MyVolley时,一定要在应用的全局的Application中进行初始化
MyVolley.init(getApplicationContext());
加载图片中涉及到的2个缓存类如下:
/** * 图片缓存类(Lru算法) * @author Yan * */
public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageCache{
private static final String TAG="BitmapLruCache";
//图片缓存的软引用
private BitmapSoftRefCache softRefCache;
public BitmapLruCache(int maxSize) {
super(maxSize);
//初始化BitmapSoftRefCache
softRefCache=new BitmapSoftRefCache();
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue,
Bitmap newValue) {
if(evicted){
//将bitmap添加到软引用的缓存中
softRefCache.putBitmap(key, oldValue);
}
}
/** * 从缓存中获取图片 */
@Override
public Bitmap getBitmap(String url) {
Bitmap bitmap=get(url);
if(bitmap==null){
//从软引用缓存中获取
bitmap=softRefCache.getBitmap(url);
}
return bitmap;
}
/** * 将图片放入到缓存中 */
@Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}
/** * 图片缓存管理类(软引用) * @author Yan * */
public class BitmapSoftRefCache implements ImageCache {
private static final String TAG="BitmapSoftRefCache";
//创建一个集合保存Bitmap
private LinkedHashMap<String,SoftReference<Bitmap>> map;
public BitmapSoftRefCache(){
map=new LinkedHashMap<>();
}
/** * 根据图片url从缓存中拿出bitmap */
@Override
public Bitmap getBitmap(String url) {
Bitmap bitmap=null;
SoftReference<Bitmap> softRef=map.get(url);
if(softRef!=null){
bitmap=softRef.get();
if(bitmap==null){
//从集合中移除
map.remove(url);
}
}
return null;
}
/** * 把图片放进缓存中 */
@Override
public void putBitmap(String url, Bitmap bitmap) {
SoftReference<Bitmap> softRef=new SoftReference<Bitmap>(bitmap);
map.put(url, softRef);
}
}
/** * 图片加载状态监听 * @author Yan * */
public class ImageListenerFactory {
private static final String TAG="ImageListenerFactory";
public static ImageListener getImageListener(final ImageView view,
final int defaultImageResId, final int errorImageResId){
return new ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
if(errorImageResId!=0){
view.setImageResource(errorImageResId);
}
}
@Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if(response.getBitmap()!=null){
if(view.getTag().toString().equals(response.getRequestUrl())){
view.setImageBitmap(response.getBitmap());
}
}
else if(defaultImageResId!=0){
view.setImageResource(defaultImageResId);
}
}
};
}
}
这里加载图片采用了LRU算法,然后配合软引用使用,这样会更好的对内存进行管理,代码中注释已经很详细,相信大家都可以理解。
/** * 返回成功监听(自定义处理逻辑) * @author Yan */
public abstract class MyReponseListener implements Response.Listener<BaseVO> {
@Override
public void onResponse(BaseVO arg0) {
onMyResponse(arg0);
}
public boolean onMyResponse(BaseVO t) {
// DialogMaker.closeProgressDialog();
// 自定义处理逻辑
...
return true;
}
}
/** * 自定义返回错误信息监听 * * @author Yan * */
public abstract class MyErrorListener implements ErrorListener {
public void onErrorResponse(VolleyError error) {
//自定义同意错误逻辑处理
...
}
}
下面提供一个请求服务器返回数据后封装成对象的一个GsonRequest:
public class GsonRequest extends Request<BaseVO>{
private static final String TAG="GsonRequest";
//超时时间,默认10秒
private int defaultHttpTimeOut=10*1000;
//回调监听
private Listener<BaseVO> listener;
//返回类型
private Type type;
//请求参数
private Map<String,String> methodBody;
/** * get请求 * * @param url * @param type * @param listener * @param errorListener */
public GsonRequest(String url, Type type, Listener<BaseVO> listener,
ErrorListener errorListener) {
super(Method.GET, url, errorListener);
// 不启用缓存(默认是true)
setShouldCache(false);
this.type = type;
this.listener = listener;
// 设置重连策略
this.setRetryPolicy(new DefaultRetryPolicy(defaultHttpTimeOut,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
}
/** * post请求 * * @param methodName * @param methodBoby * @param type * @param listener * @param errorListener */
public GsonRequest(String url, Map<String, String> methodBoby, Type type,
Listener<BaseVO> listener, ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.methodBody = methodBoby;
this.listener = listener;
this.type = type;
// 不启用缓存
setShouldCache(false);
// 设置重连策略
this.setRetryPolicy(new DefaultRetryPolicy(defaultHttpTimeOut,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
}
/** * 设置请求参数 */
@Override
protected Map<String, String> getParams() throws AuthFailureError {
if(methodBody==null){
return super.getParams();
}
//创建一个集合,保存请求参数
Map<String,String> map=new LinkedHashMap<>();
//----此处可以添加多个通用参数
//map.put(key,value);
//------
//------
//遍历集合
Iterator<Entry<String,String>> iter=methodBody.entrySet().iterator();
while(iter.hasNext()){
Entry<String, String> entry=iter.next();
map.put(entry.getKey(), entry.getValue());
}
return map;
}
/** * 将服务器返回的原生字节内容进行转换 */
@Override
protected Response<BaseVO> parseNetworkResponse(NetworkResponse response) {
try {
// 获取返回的数据(在 Content-Type首部中获取编码集,如果没有找到,默认返回 ISO-8859-1)
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(parseNetworkResponseDelegate(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
/** * 将服务器返回的内容用gson进行封装 */
private BaseVO parseNetworkResponseDelegate(String jsonString) {
return new Gson().fromJson(jsonString, type);
}
/** * 将解析后的数据进行回调 */
@Override
protected void deliverResponse(BaseVO arg0) {
listener.onResponse(arg0);
}
}
下面提供一个请求服务器返回XML格式数据后的一个XMLRequest:
**
* 服务器以XML格式返回数据
* @author Yan
*/
public class XMLRequest extends Request<XmlPullParser>{
private Listener<XmlPullParser> mListener;
public XMLRequest(int method, String url, Listener<XmlPullParser> listener,
ErrorListener errorListener){
super(method, url, errorListener);
//不启用缓存
setShouldCache(false);
mListener=listener;
}
public XMLRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
/** * 解析服务器返回的数据 */
@Override
protected Response<XmlPullParser> parseNetworkResponse(
NetworkResponse response) {
try {
String xmlString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
//创建解析工厂
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//获取解析器
XmlPullParser xmlPullParser = factory.newPullParser();
//设置解析数据
xmlPullParser.setInput(new StringReader(xmlString));
return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (XmlPullParserException e) {
return Response.error(new ParseError(e));
}
}
/** * 分发结果 */
@Override
protected void deliverResponse(XmlPullParser response) {
mListener.onResponse(response);
}
}
下面提供一个文件上传(支持多文件)的一个PostUploadRequest:
public class PostUploadRequest extends Request<String>{
/** * 正确数据的时候回掉用 */
private Listener mListener ;
/*请求 数据通过参数的形式传入*/
private List<FormImage> mListItem ;
private String BOUNDARY = "--------------520-13-14"; //数据分隔线
private String MULTIPART_FORM_DATA = "multipart/form-data";
public PostUploadRequest(String url, List<FormImage> listItem, Listener<String> listener,
ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.mListener = listener ;
setShouldCache(false);
mListItem = listItem ;
//设置请求的响应事件,因为文件上传需要较长的时间,所以在这里加大了,设为10秒
setRetryPolicy(new DefaultRetryPolicy(10*1000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
}
/** * 这里开始解析数据 * @param response Response from the network * @return */
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
try {
String mString =
new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(mString,
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
/** * 回调正确的数据 * @param response The parsed response returned by */
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
@Override
public byte[] getBody() throws AuthFailureError {
if (mListItem == null||mListItem.size() == 0){
return super.getBody() ;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
int N = mListItem.size() ;
for (int i = 0; i < N ;i++){
FormImage formImage = mListItem.get(i) ;
StringBuffer sb= new StringBuffer() ;
/*第一行*/
//`"--" + BOUNDARY + "\r\n"`
sb.append("--"+BOUNDARY);
sb.append("\r\n") ;
/*第二行*/
//Content-Disposition: form-data; name="参数的名称"; filename="上传的文件名" + "\r\n"
sb.append("Content-Disposition: form-data;");
sb.append(" name=\"");
sb.append(formImage.getName()) ;
sb.append("\"") ;
sb.append("; filename=\"") ;
sb.append(formImage.getFileName()) ;
sb.append("\"");
sb.append("\r\n") ;
/*第三行*/
//Content-Type: 文件的 mime 类型 + "\r\n"
sb.append("Content-Type: ");
sb.append(formImage.getMime()) ;
sb.append("\r\n") ;
/*第四行*/
//"\r\n"
sb.append("\r\n") ;
try {
bos.write(sb.toString().getBytes("utf-8"));
/*第五行*/
//文件的二进制数据 + "\r\n"
bos.write(formImage.getValue());
bos.write("\r\n".getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
/*结尾行*/
//`"--" + BOUNDARY + "--" + "\r\n"`
String endLine = "--" + BOUNDARY + "--" + "\r\n" ;
try {
bos.write(endLine.toString().getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
return bos.toByteArray();
}
//Content-Type: multipart/form-data; boundary=----------8888888888888
@Override
public String getBodyContentType() {
return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY;
}
}
上传文件的FormImage类如下:
public class FormImage {
//参数的名称
private String name ;
//文件名
private String fileName ;
//文件的mine
private String mime ;
//需要上传的文件
private File file ;
public FormImage() {
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getMime() {
return mime;
}
public void setMime(String mime) {
this.mime = mime;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//对文件进行二进制转换
public byte[] getValue() {
byte[] buffer = null;
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}
下面演示如何使用封装后的方法进行网络请求:
1.发送get请求:
private void getMyVolley() {
String url="http://api.k780.com:88/?app=idcard.get&idcard=110101199001011114&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";
GsonRequest request=new GsonRequest(url, PersonInfoBean.class, new MyReponseListener() {
@Override
public void onResponse(BaseVO t) {
super.onResponse(t);
PersonInfoBean bean=(PersonInfoBean) t;
Log.e("success", bean.toString());
}
}, new MyErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
super.onErrorResponse(error);
}
});
MyVolley.addRequest(request);
}
2.发送post请求:
private void postMyVolley() {
String url="http://api.k780.com:88/?app=idcard.get";
Map<String,String> map=new HashMap<>();
map.put("appkey", "10003");
map.put("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4");
map.put("format", "json");
map.put("idcard", "110101199001011114");
GsonRequest request=new GsonRequest(url, map, PersonInfoBean.class, new MyReponseListener() {
@Override
public void onResponse(BaseVO vo) {
super.onResponse(vo);
PersonInfoBean bean=(PersonInfoBean) vo;
Log.e("sucess", bean.toString());
}
}, new MyErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
super.onErrorResponse(error);
}
});
MyVolley.addRequest(request);
}
3.上传多文件演示:
//上传文件路径
String url="http://192.168.1.107:8080/FileUpload/FileServlet";
List<FormImage> list=new ArrayList<>();
String path1= Environment.getExternalStorageDirectory().getPath()+File.separator+"ss.png";
String path2= Environment.getExternalStorageDirectory().getPath()+File.separator+"ic_launcher.png";
File file1=new File(path1);
File file2=new File(path2);
FormImage f1=new FormImage();
f1.setFile(file1);
f1.setFileName("t1");
f1.setName("file1");
f1.setMime("image/png");
list.add(f1);
FormImage f2=new FormImage();
f2.setFile(file2);
f2.setFileName("t2");
f2.setName("file2");
f2.setMime("image/png");
list.add(f2);
PostUploadRequest request=new PostUploadRequest(url, list, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Log.e("success",s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
MyVolley.addRequest(request);
}
4.发送请求,服务器返回XML:
private void getXml() {
String url="http://flash.weather.com.cn/wmaps/xml/china.xml";
XMLRequest request=new XMLRequest( url, new Response.Listener<XmlPullParser>() {
@Override
public void onResponse(XmlPullParser xmlPullParser) {
try {
int eventType = xmlPullParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
String nodeName = xmlPullParser.getName();
if ("city".equals(nodeName)) {
String pName = xmlPullParser.getAttributeValue(0);
Log.e("TAG", "city is " + pName);
}
break;
}
eventType = xmlPullParser.next();
}
}catch(Exception e){
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
MyVolley.addRequest(request);
}
4.利用ImageLoader加载图片:
public class MyAdapter extends BaseAdapter{
private Context context;
private List<Person> list;
private LayoutInflater mInflater;
public ViewHolder holder;
public MyAdapter(Context context, List<Person> list) {
this.context = context;
this.list = list;
this.mInflater=LayoutInflater.from(context);
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
holder=null;
if(convertView==null){
convertView=mInflater.inflate(R.layout.itemone, null);
holder=new ViewHolder();
holder.iv_image=(ImageView) convertView.findViewById(R.id.iv_image);
holder.tv_name=(TextView) convertView.findViewById(R.id.tv_name);
convertView.setTag(holder);
}
else{
holder=(ViewHolder) convertView.getTag();
}
Person bean=list.get(position);
holder.tv_name.setText(bean.getName());
MyVolley.getImage(bean.getImgUrl(), holder.iv_image, R.mipmap.ic_launcher, R.mipmap.ic_launcher,150,150);
return convertView;
}
class ViewHolder{
private TextView tv_name;
private ImageView iv_image;
}
}
上面主要介绍了如何封装Volley,并且如何使用封装后的MyVolley进行网络请求。
演示:
今天说了这么多,相信大家一定对Volley可以达到基本掌握的情况了,本篇文章主要是从实战角度出发,主要是让大家体验一下volley的框架封装的用法,volley的源码本篇文章没有涉及到,但是这完全不影响大家使用volley,后续有时间我会从源码角度进行分析volley,说了这么多,有点饿了,今天就说到这里了,大家快快练习一下Volley的操作吧~!
VolleyDemo.zip