一、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. redis 源码阅读 数值转字符 longlong2str

    redis 在底层中会把long long转成string 再做存储. 主个功能是在sds模块里. 下面两函数是把long long 转成 char  和   unsiged long long 转成 ...

  2. Java连接程序数据源

    在实际应用中,可能需要根据表名动态地改变数据源,比如在程序数据集中,通过传进的表名参数,到数据库取出对应的表作为数据源.例如,FineReport是通过AbstractTableData抽象类来读取数 ...

  3. [转]ASP.NET Core 中间件详解及项目实战

    本文转自:http://www.cnblogs.com/savorboard/p/5586229.html 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际 ...

  4. MMORPG大型游戏设计与开发(服务器 游戏场景 掉落与网络连接)

    时间一点点的消逝,伴着自己空闲日子将要结束的时候我尽量的学习和分享场景和AI的知识给朋友们,不过很遗憾的是这些文章还有不足的地方,就是有的难点没有完全的分析到.掉落在游戏中必不可少的,同时网络连接也是 ...

  5. js实现九九乘法表

    <script type="text/javascript"> var sum=0; var wite; for (var i = 1; i < 10; i++) ...

  6. Hibernate 分组查询 子查询 原生SQL

    分组查询: 使用group by关键字对数据分组,使用having关键字对分组数据设定约束条件,从而完成对数据分组和统计 1.1 聚合函数:常被用来实现数据统计功能 ① count() 统计记录条数 ...

  7. PHP unset销毁变量并释放内存

    PHP的unset()函数用来清除.销毁变量,不用的变量,我们可以用unset()将它销毁.但是某些时候,用unset()却无法达到销毁变量占用的内存!我们先看一个例子: <?php $s=st ...

  8. on事件委托

    on绑定多个事件,off解绑事件,one事件只执行一次 on除了能够处理未来事件,还可以对事件进行委托处理 $('div').on('click', 'p', function(event)(也就是通 ...

  9. java多线程系类:JUC原子类:05之AtomicIntegerFieldUpdater原子类

    概要 AtomicIntegerFieldUpdater, AtomicLongFieldUpdater和AtomicReferenceFieldUpdater这3个修改类的成员的原子类型的原理和用法 ...

  10. Javascript四舍五入(Math.round()与Math.pow())

    代码 Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ ...