一、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. find

    语法:find [路径] [参数] [action] -name filename,查找名为filename的文件 -iname filename,查找名为filename的文件,但是不区分大小写 - ...

  2. RabbitMQ服务安装配置

    RabbitMQ是流行的开源消息队列系统,是AMQP(Advanced Message Queuing Protocol高级消息队列协议)的标准实现,用erlang语言开发.RabbitMQ据说具有良 ...

  3. scala Basic 第三课

    yield 在学习c#的时候学习过这个关键字,和这时的语义是一致的. 当你生成一个新的迭代器,而并不是想立刻使用,而是在其他地方使用的时候,可以延迟生成这个集合, 这时候yield关键字可以帮你完成这 ...

  4. ClearContainer 网络部分源码分析

    // cc-oci-runtime/src/oci.c /*! * Create the state file, apply mounts and run hooks, but do not star ...

  5. MyBatis 智能标签

    使用Where 只能标签 检索部门Y2162Dept 数据库已存在表Y2162Dept 实现动态查询 Deptno Deptname 赋值 不赋值 不赋值 赋值 赋值 赋值 不赋值 不赋值 <! ...

  6. Spring多种注入方式及注解实现DI

    一.Bean作用域 spring容器创建的时候,会将所有配置的bean对象创建出来,默认bean都是单例的.代码通过getBean()方法从容器获取指定的bean实例,容器首先会调用Bean类的无参构 ...

  7. 微软准备开源PowerShell

    微软有计划在近期内开源PowerShell 近日微软再次在向开源投出橄榄枝, PowerShell是面向Windows和Windows Server的自动化平台和脚本语言,帮助用户简化系统的管理.在纳 ...

  8. jquery的css详解(一)

    通过阅读源码可以发现css是jq的实例方法.而在内部调用jq的工具方法access来实现的,对该方法不了解的朋友请点击 -> jquery工具方法access详解 在access的回调中做了一个 ...

  9. mysql 有两种数据库引擎发音

    mysql 有两种数据库引擎 一种是 MyISAM,一种是 InnoDB MyISAM 发音为 "my-z[ei]m"; InnoDB 发音为 "in-no-db&quo ...

  10. C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 能支撑10万以上客户端的数据同步下载问题

    庞大的业务系统,特别是需要有离线作业操作支持的核心业务系统,需要有强大的基础数据同步功能,基础数据有在增加.有在变动.有在失效,同时有大量的客户端全天侯的在连接服务器.不间断的在处理核心数据. 经过2 ...