一、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. 13、Apache中虚拟目录和目录权限配置

    一.虚拟目录 之前的个人主页,为了安全起见,需要把~yanji 用户隐藏起来,这时就可以设置个 虚拟目录. 它在Apache服务器应用比较多,能够隐藏系统的真实目录,实用性非常高. 虚拟目录主要 通过 ...

  2. http status 状态码汇总

    常见HTTP状态码 200 OK 301 Moved Permanently 302 Found 304 Not Modified 307 Temporary Redirect 400 Bad Req ...

  3. FTP协议

    1. FTP协议 什么是FTP呢?FTP 是 TCP/IP 协议组中的协议之一,是英文File Transfer Protocol的缩写. 该协议是Internet文件传送的基础,它由一系列规格说明文 ...

  4. LCA 倍增||树链剖分

    方法1:倍增 1498ms #include <iostream> #include <cstdio> #include <algorithm> #include ...

  5. ArrayList,Vector,LinkedList

    在java.util包中定义的类集框架其核心的组成接口有如下:·Collection接口:负责保存单值的最大父接口 |-List子接口:允许保存重复元素,数据的保存顺序就是数据的增加顺序: |-Set ...

  6. LL(1)算法

    编译原理的语法分析中一个入门的算法就是LL(1)算法了,这里做一个总结.首先比较重要的是FIRST集和FOLLOW集合的生成. 先上个例子吧: 首先说一下FIRST集的生成,这个就要看产生式右部对应的 ...

  7. Eclipse使用svn文章列表

    http://www.cnblogs.com/duanxz/p/3334660.html http://www.cnblogs.com/duanxz/p/3334660.html http://130 ...

  8. ThreadLocal实现方式&使用介绍—无锁化线程封闭

    原文出处: xieyu_zy 虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以 ...

  9. iOS修改TextField占位符颜色大小

    UITextField *addCtrolField = [[UITextField alloc]initWithFrame:CGRectMake(CGRectGetMaxX(rightTitleLa ...

  10. 利用Highcharts插件制作动态图表

    向大家推荐一款js插件,用于绘制图表Highcharts,具体操作可参考官方网站:http://www.hcharts.cn/ 1.如下为本人制作的图形效果如下,当然其效果远不止这些,大家还可以深入研 ...