Android Volley完全解析1:初识Volley的基本用法
2017-03-15 01:56
477 查看
原文链接:http://blog.csdn.net/guolin_blog/article/details/17482165,CSDN 郭霖
不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码。于是乎,一些Android网络通信框架也就应运而生,比如说AsyncHttpClient,它把HTTP所有的通信细节全部封装在了内部,我们只需要简单调用几行代码就可以完成通信操作了。再比如Universal-Image-Loader,它使得在界面上显示网络图片的操作变得极度简单,开发者不用关心如何从网络上获取图片,也不用关心开启线程、回收图片资源等细节,Universal-Image-Loader已经把一切都做好了。
Android开发团队也是意识到了有必要将HTTP的通信操作再进行简单化,于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
下图所示的这些应用都是属于数据量不大,但网络通信频繁的,因此非常适合使用Volley。
下载完成后将它导入到你的Eclipse工程里,然后再导出一个jar包就可以了。如果你的电脑上没有Git,那么也可以直接使用我导出好的jar包,下载地址是:http://download.csdn.net/detail/sinyu890807/7152015
新建一个Android项目,将volley.jar文件复制到libs目录下,这样准备工作就算是做好了
注意这里拿到的RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
接下来为了要发出一条HTTP请求,我们还需要创建一个StringRequest对象,如下所示:
可以看到,这里new出了一个StringRequest对象,StringRequest的构造函数需要传入三个参数,第一个参数就是目标服务器的URL地址,第二个参数是服务器响应成功的回调,第三个参数是服务器响应失败的回调。其中,目标服务器地址我们填写的是百度的首页,然后在响应成功的回调里打印出服务器返回的内容,在响应失败的回调里打印出失败的详细信息。
最后,将这个StringRequest对象添加到RequestQueue里面就可以了,如下所示:
另外,由于Volley是要访问网络的,因此不要忘记在你的AndroidManifest.xml中添加如下权限:
好了,就是这么简单,如果你现在运行一下程序,并发出这样一条HTTP请求,就会看到LogCat中会打印出如下图所示的数据。
没错,百度返回给我们的就是这样一长串的HTML代码,虽然我们看起来会有些吃力,但是浏览器却可以轻松地对这段HTML代码进行解析,然后将百度的首页展现出来。
这样的话,一个最基本的HTTP发送与响应的功能就完成了。你会发现根本还没写几行代码就轻易实现了这个功能,主要就是进行了以下三步操作:
创建一个RequestQueue对象
创建一个StringRequest对象
将StringRequest对象添加到RequestQueue里面
不过大家都知道,HTTP的请求类型通常有两种,GET和POST,刚才我们使用的明显是一个GET请求,那么如果想要发出一条POST请求应该怎么做呢?StringRequest中还提供了另外一种四个参数的构造函数,其中第一个参数就是指定请求类型的,我们可以使用如下方式进行指定:
可是这只是指定了HTTP请求方式是POST,那么我们要提交给服务器的参数又该怎么设置呢?很遗憾,StringRequest中并没有提供设置POST参数的方法,但是当发出POST请求的时候,Volley会尝试调用StringRequest的父类——Request中的getParams()方法来获取POST参数,那么解决方法自然也就有了,我们只需要在StringRequest的匿名类中重写getParams()方法,在这里设置POST参数就可以了,代码如下所示:
你可能会说,每次都这样用起来岂不是很累?连个设置POST参数的方法都没有。但是不要忘记,Volley是开源的,只要你愿意,你可以自由地在里面添加和修改任何的方法,轻松就能定制出一个属于你自己的Volley版本。
至于它们的用法也基本上没有什么特殊之处,先new出一个JsonObjectRequest对象,如下所示:
可以看到,这里我们填写的URL地址是http://m.weather.com.cn/data/101010100.html,这是中国天气网提供的一个查询天气信息的接口,响应的数据就是以JSON格式返回的,然后我们在onResponse()方法中将返回的数据打印出来。
最后再将这个JsonObjectRequest对象添加到RequestQueue里就可以了,如下所示:
这样当HTTP通信完成之后,服务器响应的天气信息就会回调到onResponse()方法中,并打印出来。现在运行一下程序,发出这样一条HTTP请求,就会看到LogCat中会打印出如下图所示的数据。
由此可以看出,服务器返回给我们的数据确实是JSON格式的,并且onResponse()方法中携带的参数也正是一个JSONObject对象,之后只需要从JSONObject对象取出我们想要得到的那部分数据就可以了。
你应该发现了吧,JsonObjectRequest的用法和StringRequest的用法基本上是完全一样的,Volley的易用之处也在这里体现出来了,会了一种就可以让你举一反三,因此关于JsonArrayRequest的用法相信已经不需要我再去讲解了吧。
下图1,演示了一个请求的生命周期:
为了利用这种优势,你应该跟踪所有已经发送的请求,以便在需要的时候可以取消他们。有一个简便的方法:你可以为每一个请求对象都绑定一个tag对象。然后你可以使用这个tag来提供取消的范围。例如,你可以为你的所有请求都绑定到执行的Activity上,然后你可以在
下面一个使用String来打Tag的例子:
1、 定义你的tag并添加到你的请求任务中。
2、 在activity的onStop()方法里面,取消所有的包含这个tag的请求任务。
当取消请求时请注意:如果你依赖你的响应handler来标记状态或者触发另外一个进程,你需要对此进行考虑。再说一次,response handler是不会被执行的。
对于 app target API level 低于 API 9(Gingerbread)的使用 AndroidHttpClient。在 Gingerbread 之前,HttpURLConnection 是不可靠的。对于这个的细节,请参考 Android’s HTTP Clients。
对于 API Level 9 以及以上的,使用 HttpURLConnection。
我们可以通过检查系统版本选择合适的 HTTP Client,从而创建一个能够运行在所有 Android 版本上的应用。例如:
下面的代码片段演示了如何一步步建立一个
如果我们仅仅是想做一个单次的请求并且不想要线程池一直保留,我们可以通过使用在前面一课:发送一个简单的请求(Sending a Simple Request)文章中提到的
一个关键的概念是
下面是一个单例类,提供了
下面演示了利用单例类来执行
好了,关于Volley的基本用法就讲到这里,下篇文章中我会带领大家继续探究Volley。感兴趣的朋友请继续阅读Android Volley完全解析(二),使用Volley加载网络图片。
1. Volley简介
我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据。Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎在任何项目的代码中我们都能看到这两个类的身影,使用率非常高。不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码。于是乎,一些Android网络通信框架也就应运而生,比如说AsyncHttpClient,它把HTTP所有的通信细节全部封装在了内部,我们只需要简单调用几行代码就可以完成通信操作了。再比如Universal-Image-Loader,它使得在界面上显示网络图片的操作变得极度简单,开发者不用关心如何从网络上获取图片,也不用关心开启线程、回收图片资源等细节,Universal-Image-Loader已经把一切都做好了。
Android开发团队也是意识到了有必要将HTTP的通信操作再进行简单化,于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
下图所示的这些应用都是属于数据量不大,但网络通信频繁的,因此非常适合使用Volley。
2. 下载Volley
介绍了这么多理论的东西,下面我们就准备开始进行实战了,首先需要将Volley的jar包准备好,如果你的电脑上装有Git,可以使用如下命令下载Volley的源码:git clone https://android.googlesource.com/platform/frameworks/volley
下载完成后将它导入到你的Eclipse工程里,然后再导出一个jar包就可以了。如果你的电脑上没有Git,那么也可以直接使用我导出好的jar包,下载地址是:http://download.csdn.net/detail/sinyu890807/7152015
新建一个Android项目,将volley.jar文件复制到libs目录下,这样准备工作就算是做好了
3. StringRequest的用法
前面已经说过,Volley的用法非常简单,那么我们就从最基本的HTTP通信开始学习吧,即发起一条HTTP请求,然后接收HTTP响应。首先需要获取到一个RequestQueue对象,可以调用如下方法获取到:RequestQueue mQueue = Volley.newRequestQueue(context);
注意这里拿到的RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
接下来为了要发出一条HTTP请求,我们还需要创建一个StringRequest对象,如下所示:
StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d("TAG", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } });
可以看到,这里new出了一个StringRequest对象,StringRequest的构造函数需要传入三个参数,第一个参数就是目标服务器的URL地址,第二个参数是服务器响应成功的回调,第三个参数是服务器响应失败的回调。其中,目标服务器地址我们填写的是百度的首页,然后在响应成功的回调里打印出服务器返回的内容,在响应失败的回调里打印出失败的详细信息。
最后,将这个StringRequest对象添加到RequestQueue里面就可以了,如下所示:
mQueue.add(stringRequest);
另外,由于Volley是要访问网络的,因此不要忘记在你的AndroidManifest.xml中添加如下权限:
<uses-permission android:name="android.permission.INTERNET" />
好了,就是这么简单,如果你现在运行一下程序,并发出这样一条HTTP请求,就会看到LogCat中会打印出如下图所示的数据。
没错,百度返回给我们的就是这样一长串的HTML代码,虽然我们看起来会有些吃力,但是浏览器却可以轻松地对这段HTML代码进行解析,然后将百度的首页展现出来。
这样的话,一个最基本的HTTP发送与响应的功能就完成了。你会发现根本还没写几行代码就轻易实现了这个功能,主要就是进行了以下三步操作:
创建一个RequestQueue对象
创建一个StringRequest对象
将StringRequest对象添加到RequestQueue里面
不过大家都知道,HTTP的请求类型通常有两种,GET和POST,刚才我们使用的明显是一个GET请求,那么如果想要发出一条POST请求应该怎么做呢?StringRequest中还提供了另外一种四个参数的构造函数,其中第一个参数就是指定请求类型的,我们可以使用如下方式进行指定:
StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener);
可是这只是指定了HTTP请求方式是POST,那么我们要提交给服务器的参数又该怎么设置呢?很遗憾,StringRequest中并没有提供设置POST参数的方法,但是当发出POST请求的时候,Volley会尝试调用StringRequest的父类——Request中的getParams()方法来获取POST参数,那么解决方法自然也就有了,我们只需要在StringRequest的匿名类中重写getParams()方法,在这里设置POST参数就可以了,代码如下所示:
StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("params1", "value1"); map.put("params2", "value2"); return map; } };
你可能会说,每次都这样用起来岂不是很累?连个设置POST参数的方法都没有。但是不要忘记,Volley是开源的,只要你愿意,你可以自由地在里面添加和修改任何的方法,轻松就能定制出一个属于你自己的Volley版本。
4. JsonRequest的用法
学完了最基本的StringRequest的用法,我们再来进阶学习一下JsonRequest的用法。类似于StringRequest,JsonRequest也是继承自Request类的,不过由于JsonRequest是一个抽象类,因此我们无法直接创建它的实例,那么只能从它的子类入手了。JsonRequest有两个直接的子类,JsonObjectRequest和JsonArrayRequest,从名字上你应该能就看出它们的区别了吧?一个是用于请求一段JSON数据的,一个是用于请求一段JSON数组的。至于它们的用法也基本上没有什么特殊之处,先new出一个JsonObjectRequest对象,如下所示:
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://m.weather.com.cn/data/101010100.html", null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { Log.d("TAG", response.toString()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } });
可以看到,这里我们填写的URL地址是http://m.weather.com.cn/data/101010100.html,这是中国天气网提供的一个查询天气信息的接口,响应的数据就是以JSON格式返回的,然后我们在onResponse()方法中将返回的数据打印出来。
最后再将这个JsonObjectRequest对象添加到RequestQueue里就可以了,如下所示:
mQueue.add(jsonObjectRequest);
这样当HTTP通信完成之后,服务器响应的天气信息就会回调到onResponse()方法中,并打印出来。现在运行一下程序,发出这样一条HTTP请求,就会看到LogCat中会打印出如下图所示的数据。
由此可以看出,服务器返回给我们的数据确实是JSON格式的,并且onResponse()方法中携带的参数也正是一个JSONObject对象,之后只需要从JSONObject对象取出我们想要得到的那部分数据就可以了。
你应该发现了吧,JsonObjectRequest的用法和StringRequest的用法基本上是完全一样的,Volley的易用之处也在这里体现出来了,会了一种就可以让你举一反三,因此关于JsonArrayRequest的用法相信已经不需要我再去讲解了吧。
5. 请求的生命周期
请注意那些比较耗时的操作,例如I/O与解析parsing/decoding都是执行在工作线程。你可以在任何线程中添加一个请求,但是响应结果都是返回到主线程的。下图1,演示了一个请求的生命周期:
6. 取消请求
对请求Request对象调用cancel()方法取消一个请求。一旦取消,Volley会确保你的响应Handler不会被执行。这意味着在实际操作中你可以在activity的
onStop()方法中取消所有pending在队列中的请求。你不需要通过检测
getActivity() == null来丢弃你的响应handler,其他类似
onSaveInstanceState()等保护性的方法里面也都不需要检测。
为了利用这种优势,你应该跟踪所有已经发送的请求,以便在需要的时候可以取消他们。有一个简便的方法:你可以为每一个请求对象都绑定一个tag对象。然后你可以使用这个tag来提供取消的范围。例如,你可以为你的所有请求都绑定到执行的Activity上,然后你可以在
onStop()方法执行
requestQueue.cancelAll(this)。同样的,你可以为ViewPager中的所有请求缩略图Request对象分别打上对应Tab的tag。并在滑动时取消这些请求,用来确保新生成的tab不会被前面tab的请求任务所卡到。
下面一个使用String来打Tag的例子:
1、 定义你的tag并添加到你的请求任务中。
public static final String TAG = "MyTag"; StringRequest stringRequest; // Assume this exists. RequestQueue mRequestQueue; // Assume this exists. // Set the tag on the request. stringRequest.setTag(TAG); // Add the request to the RequestQueue. mRequestQueue.add(stringRequest);
2、 在activity的onStop()方法里面,取消所有的包含这个tag的请求任务。
@Override protected void onStop () { super.onStop(); if (mRequestQueue != null) { mRequestQueue.cancelAll(TAG); } }
当取消请求时请注意:如果你依赖你的响应handler来标记状态或者触发另外一个进程,你需要对此进行考虑。再说一次,response handler是不会被执行的。
多级别取消
RequestQueue queue = Volley.newRequestQueue(MainActivity.this); //3. 发起请求 queue.add(stringRequest); //取消单个请求 stringRequest.cancel();//取消一个请求 //取消所有请求 queue.cancelAll(null);//取消请求队列里面所有的方法 //取消置顶tag的请求 queue.cancelAll("tag1");//取消tag为tag1的一个请求 //请求添加tag-->tag的目的就是为了反查 stringRequest.setTag("tag1"); //两个不同的请求可以设置同一个tag stringRequest.setTag("tag1"); // stringRequest1.setTag("tag1");
生命周期的联动
StringRequest req2 = null; StringRequest req3 = null; StringRequest req4 = null; StringRequest req5 = null; req1.setTag(this.getClass().getSimpleName()); req2.setTag(this.getClass().getSimpleName()); req3.setTag(this.getClass().getSimpleName()); req4.setTag(this.getClass().getSimpleName()); req5.setTag(this.getClass().getSimpleName()); // 取消对应activity里面所有的请求 RequestQueue queue = VolleyTools.getInstance(MainActivity.this).getQueue(); queue.cancelAll(this.getClass().getSimpleName());// MainActivity
7. 建立网络和缓存
一个RequestQueue需要两部分来支持它的工作:一部分是网络操作,用来传输请求,另外一个是用来处理缓存操作的 Cache。在 Volley 的工具箱中包含了标准的实现方式:
DiskBasedCache提供了每个文件与对应响应数据一一映射的缓存实现。
BasicNetwork提供了一个基于 AndroidHttpClient 或者 HttpURLConnection 的网络传输。
BasicNetwork是 Volley 默认的网络操作实现方式。一个
BasicNetwork必须使用我们的 app 用于连接网络的 HTTP Client 进行初始化。这个 Client 通常是AndroidHttpClient 或者 HttpURLConnection:
对于 app target API level 低于 API 9(Gingerbread)的使用 AndroidHttpClient。在 Gingerbread 之前,HttpURLConnection 是不可靠的。对于这个的细节,请参考 Android’s HTTP Clients。
对于 API Level 9 以及以上的,使用 HttpURLConnection。
我们可以通过检查系统版本选择合适的 HTTP Client,从而创建一个能够运行在所有 Android 版本上的应用。例如:
HttpStack stack; ... // If the device is running a version >= Gingerbread... if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { // ...use HttpURLConnection for stack. } else { // ...use AndroidHttpClient for stack. } Network network = new BasicNetwork(stack);
下面的代码片段演示了如何一步步建立一个
RequestQueue:
RequestQueue mRequestQueue; // Instantiate the cache Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap // Set up the network to use HttpURLConnection as the HTTP client. Network network = new BasicNetwork(new HurlStack()); // Instantiate the RequestQueue with the cache and network. mRequestQueue = new RequestQueue(cache, network); // Start the queue mRequestQueue.start(); String url ="http://www.myurl.com"; // Formulate the request and handle the response. StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String response) { // Do something with the response } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // Handle error } }); // Add the request to the RequestQueue. mRequestQueue.add(stringRequest); ...
如果我们仅仅是想做一个单次的请求并且不想要线程池一直保留,我们可以通过使用在前面一课:发送一个简单的请求(Sending a Simple Request)文章中提到的
Volley.newRequestQueue()方法,在任何需要的时刻创建
RequestQueue,然后在我们的响应回调里面执行
stop()方法来停止操作。但是更通常的做法是创建一个
RequestQueue并设置为一个单例。下面部分将演示这种做法。
8. 使用单例模式
如果我们的应用需要持续地使用网络,更加高效的方式应该是建立一个RequestQueue的单例,这样它能够持续保持在整个 app 的生命周期中。我们可以通过多种方式来实现这个单例。推荐的方式是实现一个单例类,里面封装了
RequestQueue对象与其它的 Volley 功能。另外一个方法是继承
Application类,并在
Application.OnCreate()方法里面建立
RequestQueue。但是我们并不推荐这个方法,因为一个 static 的单例能够以一种更加模块化的方式提供同样的功能。
一个关键的概念是
RequestQueue必须使用 Application context 来实例化,而不是 Activity context。这确保了
RequestQueue在我们 app 的生命周期中一直存活,而不会因为 activity 的重新创建而被重新创建(例如,当用户旋转设备时)。
下面是一个单例类,提供了
RequestQueue与
ImageLoader功能:
public class MySingleton { private static MySingleton mInstance; private RequestQueue mRequestQueue; private ImageLoader mImageLoader; private static Context mCtx; private MySingleton(Context context) { mCtx = context; mRequestQueue = getRequestQueue(); mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() { private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(20); @Override public Bitmap getBitmap(String url) { return cache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { cache.put(url, bitmap); } }); } public static synchronized MySingleton getInstance(Context context) { if (mInstance == null) { mInstance = new MySingleton(context); } return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { // getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in. mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); } return mRequestQueue; } public <T> void addToRequestQueue(Request<T> req) { getRequestQueue().add(req); } public ImageLoader getImageLoader() { return mImageLoader; } }
下面演示了利用单例类来执行
RequestQueue的操作:
// Get a RequestQueue RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()). getRequestQueue(); ... // Add a request (in this example, called stringRequest) to your RequestQueue. MySingleton.getInstance(this).addToRequestQueue(stringRequest);
好了,关于Volley的基本用法就讲到这里,下篇文章中我会带领大家继续探究Volley。感兴趣的朋友请继续阅读Android Volley完全解析(二),使用Volley加载网络图片。
相关文章推荐
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法
- Android Volley完全解析(一),初识Volley的基本用法