一、Volley简介

Volley网络框架是Google公司在2013年发布的一款Android平台上的网络请求通信库。以下是对Volley的简单归纳。

Volley的优点:

  1. 使网络通信更快、更简单、更健壮,用Volley开发的话,开发效率会得到很大提升,开发出来的网络模块的稳定性也会非常高
  2. Get、Post网络请求及网络图像的高效率异步处理请求,Volley帮我们实现了网络请求的异步化,而且它的Get和Post请求也是非常高效的
  3. 对网络请求进行排序、优先级处理
  4. 网络请求的缓存,当网络比较缓慢时或网络情况不太好的时候,Volley可以将我们上次请求的数据进行简单的缓存,提高用户体验
  5. Volley具有多级别取消请求,当我们有多个请求在同时进行的时候,可以做到同时取消这些请求的操作,非常的方便
  6. 和Activity生命周期的联动,当Activity结束、销毁的时候,可以同时取消网络请求的操作,避免APP在后台继续进行网络请求操作,导致APP性能和用户体验都非常差

Volley的缺点:

  Volley不适合文件的上传和下载,当我们有上传和下载的需求的时候,可以考虑其他框架

为什么要使用Volley:

  1. 有高效的Get/Post方式的数据请求交互(效率非常高)
  2. 网络图片的加载和缓存(不使用Volley的情况下进行网络图片的处理会非常的麻烦,而且非常容易造成内存溢出,如果使用Volley,可以自动为图片进行缓存,不但节省流量,而且提高APP的性能)
  3. 是Google官方推出的针对Android平台的专用的网络通信库,Google的团队网络请求这部分优化的是非常好的,非常权威
  4. 性能很稳定,效率很强劲

使用Volley从服务器端获取数据的几种方式:

  1. StringRequest:对请求返回的数据类型不确定的情况下使用,涵盖了后面的两种请求对象
  2. JsonObjectRequest:确定请求返回的数据类型是JsonObject时使用,解析效率比StringRequest高一些
  3. JsonArrayRequest:确定求求返回的数据类型是JsonArray时使用

本帖解决的有关Volley的五个问题:

  1. Volley的Get和Post请求方式的使用
  2. Volley的网络请求队列的建立和取消队列请求
  3. Volley与Activity生命周期的联动
  4. Volley的简单二次封装
  5. Volley获取网络图片

二、Volley的网络请求队列的建立和取消队列请求

  我们可以建立一个全局的请求队列,再在需要的时候建立一个请求,并将这个请求加入到请求队列中,这样一来整个APP的请求都可以通过这个队列来管理。因为Volley有全局请求队列这一功能,所以Volley更适合于并发的、对效率和性能要求非常好的场景。我们需要建立一个请求队列所在的全局类(继承自Application类),代码如下:

 1 public class MyApplication extends Application {
2 private static RequestQueue queue; // Volley的全局请求队列
3
4 @Override
5 public void onCreate() {
6 super.onCreate();
7 // 创建Application的同时初始化Volley全局请求队列
8 queue = Volley.newRequestQueue(getApplicationContext());
9 }
10
11 // 静态方法返回Volley全局请求队列
12 public static RequestQueue getRequestQueue() {
13 return queue;
14 }
15 }

请求队列所在的全局类MyApplication

  因为涉及到Application的关系,所以我们需要在AndroidMenifest文件的<application>标签中添加application的引用: android:name=".com.tools.MyApplication" 。另外,因为使用Volley需要使用网络,所以我们还需要为项目添加网络权限: <uses-permission android:name="android.permission.INTERNET" /> 。下面贴出AndroidMenifest文件中的所有代码:

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.activity.volleyclient"> <uses-permission android:name="android.permission.INTERNET" /> <application
android:name=".com.tools.MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.NoTitleBar">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>

AndroidMenifest文件中的代码

  到此为止,我们就已经创建好了请求队列。我们通过 MyApplication.getRequestQueue().add(stringRequestGet); 来向请求队列中添加请求(注意在添加之前必须为每个请求设置TAG标记,以便删除);用 MyApplication.getRequestQueue().cancelAll("tag"); 来删除请求队列中的请求。

三、Volley的GET和POST请求方式的使用

  上面提到过,Volley获取服务端代码有三种方式:StringRequest、JsonObjectRequest和JsonArrayRequest。由于这三种方式的代码基本一样,而且后两种相比于第一种也有一定的局限性,所以这里就以StringRequest为例,贴出程序源码和结果。

 public class MainActivity extends Activity {
// 基本的URL地址(GET和POST都用到这个地址,只不过GET需要在URL上添加参数,而POST不需要)
private static final String BASE_URL = "http://192.168.1.102:8080/VolleyServer/JsonServlet";
private TextView result; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
result = (TextView) findViewById(R.id.result); volleyGet();
volleyPost();
} // 使用GET方式从服务端获取到JSON数据并加以解析
private void volleyGet() {
// 使用StringRequest获取JSON数据
String url = BASE_URL + "?key=person";
StringRequest stringRequestGet = new StringRequest(Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
addTextToResult("-->使用StringRequest用Get方式获取JSON数据\n");
manageResponse(response);
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
addTextToResult(volleyError.toString());
}
});
// 给Volley的Request请求对象标注TAG,并加入到全局请求队列中
stringRequestGet.setTag("StringRequestGet");
MyApplication.getRequestQueue().add(stringRequestGet);
} // 使用POST方式从服务端获取到JSON数据并加以解析
private void volleyPost() {
// 使用StringRequest获取JSON数据
String url = BASE_URL;
StringRequest stringRequestPost = new StringRequest(Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
addTextToResult("-->使用StringRequest用Post方式获取JSON数据\n");
manageResponse(response);
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
addTextToResult(volleyError.toString());
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> hashMap = new HashMap<>();
hashMap.put("key", "person");
return hashMap;
}
};
stringRequestPost.setTag("StringRequestPost");
MyApplication.getRequestQueue().add(stringRequestPost);
} // 将参数中的文本添加到界面上的TextView中(在原文本的基础上添加)
private void addTextToResult(String text) {
String currentText = result.getText().toString();
currentText += text;
result.setText(currentText);
} // 将使用Volley获取到的服务端JSON数据进行解析后添加到结果TextView中
private void manageResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response).getJSONObject("person");
addTextToResult("姓名:" + jsonObject.getString("name") + "\n年龄:" + jsonObject.getInt("age") + "\n地址:" +
jsonObject.getString("address") + "\n\n");
} catch (Exception e) {
e.printStackTrace();
}
} @Override
protected void onStop() {
// 结束Activity的同时销毁全局请求队列中的所有请求
super.onStop();
MyApplication.getRequestQueue().cancelAll("StringRequestGet");
MyApplication.getRequestQueue().cancelAll("StringRequestPost");
}
}

主界面MainActivity代码

运行结果如下:

四、Volley与Activity生命周期的联动

  所谓的和Activity生命周期的联动,就是在Activity被销毁的时候(调用Activity的onStop()方法的时候),同时销毁所有的Volley请求对象。代码已经包含在MainActivity的代码中,这里再贴一遍:

 @Override
protected void onStop() {
// 结束Activity的同时销毁全局请求队列中的所有请求
super.onStop();
MyApplication.getRequestQueue().cancelAll("StringRequestGet");
MyApplication.getRequestQueue().cancelAll("StringRequestPost");
}

MainActivity的OnStop()方法

五、Volley的简单的二次封装

  所谓的“二次封装”,就是把上面我们所做的工作——包括实例化StringRequest、为Request添加TAG、将Request放入请求队列中灯操作——都封装成一个类或一个方法,以便以后调用。为了达到封装的目的,我们需要建立两个类:第一个类是VolleyInterface抽象类,用来定义请求成功和请求失败的接口,通过接口回调,让用户可以在主界面自定义实现操作;第二个类是VolleyRequest类,封装GET和POST两种请求方式的模糊代码,结合VolleyInterface类中的接口,完成封装。以下是这两个类的代码:

 public abstract class VolleyInterface {
private Context context;
public static Response.Listener<String> listener; // 请求成功的监听器
public static Response.ErrorListener errorListener; // 请求失败的监听器 public VolleyInterface(Context context, Response.Listener<String> listener, Response.ErrorListener errorListener) {
this.context = context;
this.listener = listener;
this.errorListener = errorListener;
} // 提供给用户编写的请求成功后的操作的接口
public abstract void onSuccess(String response); // 提供给用户编写的请求失败后的操作的接口
public abstract void onError(VolleyError error); // 利用接口回调,封装StringRequest中的请求成功的接口
public Response.Listener<String> loadingListener() {
listener = new Response.Listener<String>() {
@Override
public void onResponse(String response) {
onSuccess(response);
}
};
return listener;
} // 利用接口回调,封装StringRequest中的请求失败的接口
public Response.ErrorListener loadingErrorListener() {
errorListener = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
onError(error);
}
};
return errorListener;
}
}

抽象类VolleyInterface中的代码

 public class VolleyRequest {
private static StringRequest request;
private static Context context; // 使用StringRequest用GET方式从服务端获取JSON数据的封装方法
public static void RequestGet(Context context, String url, String tag, VolleyInterface vif) {
MyApplication.getRequestQueue().cancelAll(tag);
request = new StringRequest(Request.Method.GET, url, vif.loadingListener(), vif.loadingErrorListener());
request.setTag(tag);
MyApplication.getRequestQueue().add(request);
MyApplication.getRequestQueue().start();
} // 使用StringRequest用POST方式从服务端获取JSON数据的封装方法
public static void RequestPost(Context context, String url, String tag, final Map<String, String> params, VolleyInterface vif) {
MyApplication.getRequestQueue().cancelAll(tag);
request = new StringRequest(Request.Method.POST, url, vif.loadingListener(), vif.loadingErrorListener()) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
return params;
}
};
request.setTag(tag);
MyApplication.getRequestQueue().add(request);
MyApplication.getRequestQueue().start();
}
}

VolleyRequest类中的代码

以下是MainActivity类中的测试代码:

 public class MainActivity extends Activity {
// 基本的URL地址(GET和POST都用到这个地址,只不过GET需要在URL上添加参数,而POST不需要)
private static final String BASE_URL = "http://192.168.1.102:8080/VolleyServer/JsonServlet";
private TextView result; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
result = (TextView) findViewById(R.id.result); volleyGet();
volleyPost();
customGet();
customPost();
} // 使用GET方式从服务端获取到JSON数据并加以解析
private void volleyGet() {
// 使用StringRequest获取JSON数据
String url = BASE_URL + "?key=person";
StringRequest stringRequestGet = new StringRequest(Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
addTextToResult("-->使用StringRequest用Get方式获取JSON数据\n");
manageResponse(response);
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
addTextToResult(volleyError.toString());
}
});
// 给Volley的Request请求对象标注TAG,并加入到全局请求队列中
stringRequestGet.setTag("StringRequestGet");
MyApplication.getRequestQueue().add(stringRequestGet);
} // 使用POST方式从服务端获取到JSON数据并加以解析
private void volleyPost() {
// 使用StringRequest获取JSON数据
String url = BASE_URL;
StringRequest stringRequestPost = new StringRequest(Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
addTextToResult("-->使用StringRequest用Post方式获取JSON数据\n");
manageResponse(response);
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
addTextToResult(volleyError.toString());
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> hashMap = new HashMap<>();
hashMap.put("key", "person");
return hashMap;
}
};
stringRequestPost.setTag("StringRequestPost");
MyApplication.getRequestQueue().add(stringRequestPost);
} // 使用二次封装的方法进行GET请求
private void customGet() {
VolleyRequest.RequestGet(this, BASE_URL + "?key=person", "CustomRequestGet", new VolleyInterface(this, VolleyInterface.listener, VolleyInterface.errorListener) {
@Override
public void onSuccess(String response) {
addTextToResult("-->使用VolleyRequest用GET方式获取JSON数据\n");
manageResponse(response);
} @Override
public void onError(VolleyError error) {
addTextToResult(error.toString());
}
});
} // 使用二次封装的方法进行POST请求
private void customPost() {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("key", "person");
VolleyRequest.RequestPost(this, BASE_URL, "CustomRequestPost", hashMap, new VolleyInterface(this, VolleyInterface.listener, VolleyInterface.errorListener) {
@Override
public void onSuccess(String response) {
addTextToResult("-->使用VolleyRequest用POST方式获取JSON数据\n");
manageResponse(response);
} @Override
public void onError(VolleyError error) {
addTextToResult(error.toString());
}
});
} // 将参数中的文本添加到界面上的TextView中(在原文本的基础上添加)
private void addTextToResult(String text) {
String currentText = result.getText().toString();
currentText += text;
result.setText(currentText);
} // 将使用Volley获取到的服务端JSON数据进行解析后添加到结果TextView中
private void manageResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response).getJSONObject("person");
addTextToResult("姓名:" + jsonObject.getString("name") + "\n年龄:" + jsonObject.getInt("age") + "\n地址:" +
jsonObject.getString("address") + "\n\n");
} catch (Exception e) {
e.printStackTrace();
}
} @Override
protected void onStop() {
// 结束Activity的同时销毁全局请求队列中的所有请求
super.onStop();
MyApplication.getRequestQueue().cancelAll("StringRequestGet");
MyApplication.getRequestQueue().cancelAll("StringRequestPost");
MyApplication.getRequestQueue().cancelAll("CustomRequestGet");
MyApplication.getRequestQueue().cancelAll("CustomRequestPost");
}
}

第二次测试的代码

运行结果如下图所示:

六、Volley获取网络图片

  Volley获取网络图片有三种方式。第一种是使用ImageRequest获取网络图片,加载到Android自带的ImageView中;第二种是使用ImageLoader结合图片缓存获取网络图片,加载到Android自带的ImageView中;第三种是使用ImageLoader结合图片缓存获取网络图片,加载到Volley中提供的NetworkImageView中。下面是将这三种方法在同一个Activity中演示的代码:

 public class MainActivity extends Activity {
private static final String IMAGE_URL = "http://www.baidu.com/img/bdlogo.png";
private ImageView image, image2;
private NetworkImageView image3; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
image = (ImageView) findViewById(R.id.image);
image2 = (ImageView) findViewById(R.id.image2);
image3 = (NetworkImageView) findViewById(R.id.image3); // Volley加载网络图片
volleyImageLoad();
volleyImageCache();
volleyNetworkImageLoad();
} // 使用ImageRequest获取网络图片,加载到Android自带的ImageView中
private void volleyImageLoad() {
ImageRequest request = new ImageRequest(IMAGE_URL, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
image.setImageBitmap(bitmap);
}
}, 100, 100, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
image.setImageResource(R.mipmap.ic_launcher);
}
});
request.setTag("ImageRequest");
MyApplication.getRequestQueue().add(request);
} // 使用ImageLoader结合图片缓存获取网络图片,加载到Android自带的ImageView中
private void volleyImageCache() {
ImageLoader imageLoader = new ImageLoader(MyApplication.getRequestQueue(), new BitmapCache());
ImageLoader.ImageListener listener = imageLoader.getImageListener(image2, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
imageLoader.get(IMAGE_URL, listener);
} // 使用ImageLoader结合图片缓存获取网络图片,加载到Volley中提供的NetworkImageView中
private void volleyNetworkImageLoad() {
ImageLoader imageLoader = new ImageLoader(MyApplication.getRequestQueue(), new BitmapCache());
image3.setDefaultImageResId(R.mipmap.ic_launcher);
image3.setErrorImageResId(R.mipmap.ic_launcher);
image3.setImageUrl(IMAGE_URL, imageLoader);
} @Override
protected void onStop() {
// 结束Activity的同时销毁全局请求队列中的所有请求
super.onStop();
MyApplication.getRequestQueue().cancelAll("ImageRequest");
}
}

MainActivity的代码

 public class BitmapCache implements ImageLoader.ImageCache {
public LruCache<String, Bitmap> cache;
public int maxCacheLength = 10 * 1024 * 1024; @SuppressLint("NewApi")
public BitmapCache() {
cache = new LruCache<String, Bitmap>(maxCacheLength) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
} @SuppressLint("NewApi")
@Override
public Bitmap getBitmap(String key) {
return cache.get(key);
} @SuppressLint("NewApi")
@Override
public void putBitmap(String key, Bitmap value) {
cache.put(key, value);
}
}

图片缓存类BitmapCache

运行结果如下图所示:

注:第一张图是模糊的,可见用ImageRequest获取到的图片质量不如后两种方法。

最后附上  Volley用到的JAR包

Android网络请求通信之Volley的更多相关文章

  1. Android网络编程系列之Volley总结

    前言 Volley的中文翻译为“齐射.并发”,是在2013年的Google大会上发布的一款Android平台网络通信库,具有网络请求的处理.小图片的异步加载和缓存等功能,能够帮助 Android AP ...

  2. xamarin android网络请求总结

    xamarin android中网络请求的框架非常多,在项目中使用的是第三方的一个网络请求框架restsharp,应该是github上.net网络请求最多star的框架,没有之一.这里就简单汇总了其他 ...

  3. Android 网络请求及数据处理

    Android 网络请求: 1.Volley   http://blog.csdn.net/t12x3456/article/details/9221611 2.Android-Async-Http  ...

  4. Android网络请求框架AsyncHttpClient实例详解(配合JSON解析调用接口)

    最近做项目要求使用到网络,想来想去选择了AsyncHttpClient框架开进行APP开发.在这里把我工作期间遇到的问题以及对AsyncHttpClient的使用经验做出相应总结,希望能对您的学习有所 ...

  5. 【安卓网络请求开源框架Volley源码解析系列】定制自己的Request请求及Volley框架源码剖析

    通过前面的学习我们已经掌握了Volley的基本用法,没看过的建议大家先去阅读我的博文[安卓网络请求开源框架Volley源码解析系列]初识Volley及其基本用法.如StringRequest用来请求一 ...

  6. Android 网络请求框架Retrofit

    Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp ...

  7. Android 网络请求Retrofit + RxJava

    一.背景 经常看到项目用Retrofit+RxJava+RxAndroid的框架,为了看懂项目的结构.现在来了解一下,Retrofit: Retrofit是Square 公司开发的一款正对Androi ...

  8. android网络请求库volley方法详解

    使用volley进行网络请求:需先将volley包导入androidstudio中 File下的Project Structrue,点加号导包 volley网络请求步骤: 1. 创建请求队列     ...

  9. Android进阶笔记02:Android 网络请求库的比较及实战(二)

    一.Volley        既然在android2.2之后不建议使用HttpClient,那么有没有一个库是android2.2及以下版本使用HttpClient,而android2.3及以上版本 ...

随机推荐

  1. Python3的decode()与encode()

    python3的decode()与encode() Tags: Python Python3 对于从python2.7过来的人,对python3的感受就是python3对文本以及二进制数据做了比较清晰 ...

  2. 【C#】【Thread】SpinWait

    System.Threading.SpinWait 是一个轻量同步类型,可以在低级别方案中使用它来避免内核事件所需的高开销的上下文切换和内核转换. 在多核计算机上,当预计资源不会保留很长一段时间时,如 ...

  3. Microsoft Client Development MVP 2013 - 2014

    周末一直沉浸在醉意中,为婚礼忙忙碌碌了一个月,终于完成了人生一大喜事. 清晨仍旧有一些宿醉得感觉, 看到来自微软的邮件,获得Microsoft Client Development MVP 2013 ...

  4. Python list

    序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推. Python有6个序列的内置类型,但最常见的是列表和元组. 序列 ...

  5. js小数点失精算法修正

    在用js计算0.07*100时候竟然=7.000000000000001 关于js失精算法你都遇到哪些,让我们一起来细数一下吧 console.log(0.07*100); // 7.00000000 ...

  6. js通过日期计算属于星期几

    var arys1 = new Array(); arys1 = "2016-09-25".split('-'); //日期为输入日期,格式为 2013-3-10 var ssda ...

  7. bootstrap快速搭建属于自己的后台模板库

    不论做什么项目,我们都以快速搭建为主,设计师固然重要,但是,我们前端开发的也必须能给出自己以前做过什么样的模板,自己收藏的模板,或者我们弹框的形式,我的提示框的形式,我用的下拉框的插件,日历的插件,我 ...

  8. Linux 下配置php开发环境

    windows下有一键安装的环境很方便,不过现实中常常服务器是linux系统.想要搭建环境怎么搞呢? 边学变发直播博客,不定期更新.

  9. [转]Ext ComboBox 默认选中某一项

    原文地址:http://blog.csdn.net/liuguxing/article/details/8623190 项目中经常用到选择框,需要从后台异步加载数据,可单独写一个组件进行加载 App. ...

  10. 【原创】cs+html+js+css模式(六):改造ajax.js,从原来的原生态js修改为依赖于jquery插件

          由于原有的ajax可能在性能上,对于jquery的支持不够并且不够方便,开发人员使用的时候需要知道我们内部指定的后缀文件的设置,基于这个前提我们进行了js的改造 // 使用闭包开发插件 ( ...