Android网络请求通信之Volley
一、Volley简介
Volley网络框架是Google公司在2013年发布的一款Android平台上的网络请求通信库。以下是对Volley的简单归纳。
Volley的优点:
- 使网络通信更快、更简单、更健壮,用Volley开发的话,开发效率会得到很大提升,开发出来的网络模块的稳定性也会非常高
- Get、Post网络请求及网络图像的高效率异步处理请求,Volley帮我们实现了网络请求的异步化,而且它的Get和Post请求也是非常高效的
- 对网络请求进行排序、优先级处理
- 网络请求的缓存,当网络比较缓慢时或网络情况不太好的时候,Volley可以将我们上次请求的数据进行简单的缓存,提高用户体验
- Volley具有多级别取消请求,当我们有多个请求在同时进行的时候,可以做到同时取消这些请求的操作,非常的方便
- 和Activity生命周期的联动,当Activity结束、销毁的时候,可以同时取消网络请求的操作,避免APP在后台继续进行网络请求操作,导致APP性能和用户体验都非常差
Volley的缺点:
Volley不适合文件的上传和下载,当我们有上传和下载的需求的时候,可以考虑其他框架
为什么要使用Volley:
- 有高效的Get/Post方式的数据请求交互(效率非常高)
- 网络图片的加载和缓存(不使用Volley的情况下进行网络图片的处理会非常的麻烦,而且非常容易造成内存溢出,如果使用Volley,可以自动为图片进行缓存,不但节省流量,而且提高APP的性能)
- 是Google官方推出的针对Android平台的专用的网络通信库,Google的团队网络请求这部分优化的是非常好的,非常权威
- 性能很稳定,效率很强劲
使用Volley从服务器端获取数据的几种方式:
- StringRequest:对请求返回的数据类型不确定的情况下使用,涵盖了后面的两种请求对象
- JsonObjectRequest:确定请求返回的数据类型是JsonObject时使用,解析效率比StringRequest高一些
- JsonArrayRequest:确定求求返回的数据类型是JsonArray时使用
本帖解决的有关Volley的五个问题:
- Volley的Get和Post请求方式的使用
- Volley的网络请求队列的建立和取消队列请求
- Volley与Activity生命周期的联动
- Volley的简单二次封装
- 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的更多相关文章
- Android网络编程系列之Volley总结
前言 Volley的中文翻译为“齐射.并发”,是在2013年的Google大会上发布的一款Android平台网络通信库,具有网络请求的处理.小图片的异步加载和缓存等功能,能够帮助 Android AP ...
- xamarin android网络请求总结
xamarin android中网络请求的框架非常多,在项目中使用的是第三方的一个网络请求框架restsharp,应该是github上.net网络请求最多star的框架,没有之一.这里就简单汇总了其他 ...
- Android 网络请求及数据处理
Android 网络请求: 1.Volley http://blog.csdn.net/t12x3456/article/details/9221611 2.Android-Async-Http ...
- Android网络请求框架AsyncHttpClient实例详解(配合JSON解析调用接口)
最近做项目要求使用到网络,想来想去选择了AsyncHttpClient框架开进行APP开发.在这里把我工作期间遇到的问题以及对AsyncHttpClient的使用经验做出相应总结,希望能对您的学习有所 ...
- 【安卓网络请求开源框架Volley源码解析系列】定制自己的Request请求及Volley框架源码剖析
通过前面的学习我们已经掌握了Volley的基本用法,没看过的建议大家先去阅读我的博文[安卓网络请求开源框架Volley源码解析系列]初识Volley及其基本用法.如StringRequest用来请求一 ...
- Android 网络请求框架Retrofit
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp ...
- Android 网络请求Retrofit + RxJava
一.背景 经常看到项目用Retrofit+RxJava+RxAndroid的框架,为了看懂项目的结构.现在来了解一下,Retrofit: Retrofit是Square 公司开发的一款正对Androi ...
- android网络请求库volley方法详解
使用volley进行网络请求:需先将volley包导入androidstudio中 File下的Project Structrue,点加号导包 volley网络请求步骤: 1. 创建请求队列 ...
- Android进阶笔记02:Android 网络请求库的比较及实战(二)
一.Volley 既然在android2.2之后不建议使用HttpClient,那么有没有一个库是android2.2及以下版本使用HttpClient,而android2.3及以上版本 ...
随机推荐
- 常用Linux命令记录
[RSYNC] 指定SSH端口从远程服务器同步文件至本地目录 rsync -avH --progress '-e ssh -p 3600' user@remote_ip:remote_dir loc ...
- 推荐一些python Beautiful Soup学习网址
前言:这几天忙着写分析报告,实在没精力去研究django,虽然抽时间去看了几遍中文文档,还是等实际实践后写几篇操作文章吧! 正文:以下是本人前段时间学习bs4库找的一些网址,在学习的可以参考下,有点多 ...
- 你不知道的Javascript(上卷)读书笔记之一 ---- 作用域
你不知道的Javascript(上卷)这本书在我看来是一本还不错的书籍,这本书用比较简洁的语言来描述Js的那些"坑",在这里写一些博客记录一下笔记以便消化吸收. 1 编译原理 在此 ...
- GLine游戏(Win32GUI实现,CodeBlocks+GCC编译)
游戏规则: 在10X10的棋盘上有五种颜色的棋子. 点击一个棋子,再点击一个空格子,如果两者之间有一条路径的话,棋子会移动到空格子内. 每移动一次,棋盘上会增加三个棋子,其位置和颜色都是随机的. 当横 ...
- POJ3250[USACO2006Nov]Bad Hair Day[单调栈]
Bad Hair Day Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 17774 Accepted: 6000 Des ...
- zookeeper安装
http://blog.itpub.net/27099995/viewspace-1394831/ http://blog.csdn.net/huwei2003/article/details/491 ...
- 用C#调用C++DLL(x64),总是提示找不到DLL
用C#调用自己写的C++ DLL(x64),总是提示找不到DLL,调试可以,发布release老是提示找不到DLL(dll文件确定存在) 原因:Visual C++的DLL分发方式没选:调试默认选择: ...
- IIS 设置默认首页静态页,无静态页,走路由
在Global.asax文件中添加 protected void Application_BeginRequest(Object sender, EventArgs e) { ...
- mysql 加锁测试
今天研究cobar,做执行时间测试,需要对表记录加锁.用了以下两种方式为表记录加锁. 第一种方式: begin; //开始事务 select * from 表名 ( where ……) for ...
- 你可能不知道的 NaN 以及 underscore 1.8.3 _.isNaN 的一个 BUG
这篇文章并不在我的 underscore 源码解读计划中,直到 @pod4g 同学回复了我的 issue(详见 https://github.com/hanzichi/underscore-analy ...