文档章节

【安卓网络请求开源框架Volley源码解析系列】初识Volley及其基本用法

htq
 htq
发布于 2016/07/26 09:38
字数 3286
阅读 17
收藏 0
点赞 0
评论 0

在安卓中当涉及到网络请求时,我们通常使用的是HttpUrlConnection与HttpClient这两个类,网络请求一般是比较耗时,因此我们通常会在一个线程中来使用,但是在线程中使用这两个类时就要考虑到如何将处理结果传出去,通常的解决方法就是采用接口回调技术来解决,代码如下:

public static void doGetRequest(final String uri,final HttpCallbackListener listener) throws IOException
	{
		new Thread(){
			public void run ()
			{
				URL url;
				try {
					url = new URL(uri);
					HttpURLConnection  connection=(HttpURLConnection) url.openConnection();
					//	connection.setDoInput(true);
					//    connection.setRequestMethod("GET");
					    connection.connect();//必须加上该语句
						InputStream is=connection.getInputStream();
						BufferedReader reader=new BufferedReader(new InputStreamReader(is));
						StringBuilder buffer=new StringBuilder();
						String line;
						while((line=reader.readLine())!=null)
						{
							buffer.append(line);
							
						}
						if(listener!=null)
						{

							listener.onComplete(buffer.toString());
						}
				} catch (MalformedURLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
			}
		}.start();
		
		
		
	}

在上述的doGetRequest()方法中的第二个参数即为一个回调接口,关于接口回调不是本博客的重点,因此不过多赘述。可以看到这样处理起来非常的繁琐,必须自己先定义一个接口,在接口中定义一些方法,然后还得将该接口作为doGetRequest()方法一个参数,在该方法中调用接口中定义的方法,最后在具体使用doGetRequest()时还得自己创建一个实现了该接口的实例类对象来具体执行接口中的方法。

当然如果涉及到一些复杂数据的请求,那就更加繁琐了,如图片,xml或json类型的数据,而事实上在网络通信中这些数据的请求也相当的频繁。因此谷歌在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。也就是本博客的主角。

一初识Volley

Volley 是 Google 推出的轻量级 Android 异步网络请求框架和图片加载框架。在 Google I/O 2013 大会上发布。其适用场景是数据量小,通信频繁的网络操作。

主要特点:
(1). 扩展性强。Volley 中大多是基于接口的设计,可配置性强。
(2). 一定程度符合 Http 规范,包括返回 ResponseCode(2xx、3xx、4xx、5xx)的处理,请求头的处理,缓存机制的支持等。并支持重试及优先级定义。
(3). 默认 Android2.3 及以上基于 HttpURLConnection,2.3 以下基于 HttpClient 实现。
    原因如下:
在 Froyo(2.2) 之前,HttpURLConnection 有个重大 Bug,调用 close() 函数会影响连接池,导致连接复用失效,所以在 Froyo 之前使用 HttpURLConnection 需要关闭 keepAlive。另外在 Gingerbread(2.3) HttpURLConnection 默认开启了 gzip 压缩,提高了 HTTPS 的性能,Ice Cream Sandwich(4.0) HttpURLConnection 支持了请求结果缓存。再加上 HttpURLConnection 本身 API 相对简单,所以对 Android 来说,在 2.3 之后建议使用 HttpURLConnection,之前建议使用 AndroidHttpClient。
(4). 提供简便的图片加载工具。

二Volley的基本用法:

正如我在上述所介绍的那样,网络中的请求一般包括文本请求,json数据请求与图片请求。下面我们一一介绍:

1StringRequest:首先我们来看一下类的定义:

public class StringRequest extends Request<String>
可以看到它继承自Request类,之所以谈到这个是因为后续讲解的JsonRequest也是继承自Requese。这也是为何它们用法非常相似的一个原因。


再来看一下StringRequest的构造函数:

public StringRequest(int method, String url, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }

public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }
下面是基于第二种构造函数的使用StringRequest的代码:

RequestQueue mQueue = Volley.newRequestQueue(context);

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);
							}
						});
mQueue.add(stringRequest);
从上述代码可以看到使用StringRequest来获取文本请求包括三个步骤:

1创建一个RequestQueue对象,调用Volley.newRequestQueue(context);即可得到一个RequestQueue对象。

2创建一个StringRequest对象,StringRequest的构造函数需要传入三个参数,因为网咯通信使用的是HTTP协议,因此第一个参数就是目标服务器的URL地址,第二个参数是服务器响应成功的回调,第三个参数是服务器响应失败的回调。其中,目标服务器地址我们填写的是百度的首页,然后在响应成功的回调里打印出服务器返回的内容,在响应失败的回调里打印出失败的详细信息。

3将StringRequest对象添加到RequestQueue对象中,即mQueue.add(stringRequest).


注意Volley是要访问网络的,因此不要忘记在你的AndroidManifest.xml中添加如下权限:

<uses-permission android:name="android.permission.INTERNET" />

显然上述代码是用来从服务器端获取数据的,我们知道HTTP请求包含两种最基本的请求方式,即POST与GET。显然上述代码表示的是get请求,那么如何发送post请求呢?

这就需要用到Volley的另一个构造函数了:

StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener);

该函数比前面的那个构造函数多了一个参数,即Method.POST用来表示是一个post请求,

可是这只是指定了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("baidu", "baidu");
		map.put("tencent", "tencent");
		return map;
	}
};



2JsonRequest:首先我们来看一下类的定义:

public abstract class JsonRequest<T> extends Request<T>
可以看到与StringRequest一样,它也是继承自Request的,而且它是一个抽象类,也就是我们不能直接实例化它,而应该实例化其子类,JsonRequest包含两个子类:JsonArrayRequest与JsonObjectRequest。这也很好理解,分别对应json中的JsonArray与JsonObject。

再来看一下JsonObjectRequest的构造函数:

public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
            Listener<JSONObject> listener, ErrorListener errorListener) {
        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
                    errorListener);
    }

 public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,
            ErrorListener errorListener) {
        this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,
                listener, errorListener);
    }
可以看到几乎与StringRequest一模一样,都包括两种构造函数,一种用来执行get请求一种用来执行post请求,其实不光构造函数与StringRequest一模一样,其用法也与StringRequest一模一样,只不过在StringRequest的三个步骤中的第二部创建一个JsonObjectRequest对象,代码如下:

RequestQueue mQueue = Volley.newRequestQueue(context);

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);
			}
		});
mQueue.add(jsonObjectRequest);

注意当获取数据成功时会回调第二个参数Listener接口,该接口中的onResponse()方法中携带的参数是一个JSONObject对象,因此只需要从JSONObject对象取出我们想要得到的那部分数据就可以了。

至于JsonObjectRequest与JsonObjectRequest用法几乎完全相同,在此不再赘述。

另外注意在JsonObjectRequest中存在一个重要的方法:protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) 该方法位于其父类Request中,即Request的子类都包含该方法,这个方法可以用来处理中文乱码问题,如在本人的仿腾讯QQ的IM通讯APP中的QQ天气模块开发时就遇到过中文乱码问题,即使用Volley从中国天气网提供接口获取到的数据显示出来是乱码,但是使用HttpUrlConnection则不会出现此问题。此时我们只需要自定义一个类继承自JsonObjectRequest

然后重写其 parseNetworkResponse()方法,在该方法中指定使用"UTF-8"格式即可。代码如下:

public static class CharsetJsonRequest extends JsonObjectRequest {

	    public CharsetJsonRequest(String url, JSONObject jsonRequest,
	            Listener<JSONObject> listener, ErrorListener errorListener) {
	        super(url, jsonRequest, listener, errorListener);
	    }

	    public CharsetJsonRequest(int method, String url, JSONObject jsonRequest,
	            Listener<JSONObject> listener, ErrorListener errorListener) {
	        super(method, url, jsonRequest, listener, errorListener);
	    }

	    @Override
	    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {

	        try {
	            String jsonString = new String(response.data, "UTF-8");
	            return Response.success(new JSONObject(jsonString),
	                    HttpHeaderParser.parseCacheHeaders(response));
	        } catch (UnsupportedEncodingException e) {
	            return Response.error(new ParseError(e));
	        } catch (JSONException je) {
	            return Response.error(new ParseError(je));
	        }
	    }

	}



3ImageRequest.:
首先我们来看一下类的定义:

public class ImageRequest extends Request<Bitmap>
可以看到ImageRequest.也是继承自Request,那么你也应该想到它的使用与StringRequest几乎完全相同。

我们来看一下其构造函数:

public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,
            Config decodeConfig, Response.ErrorListener errorListener) {
        super(Method.GET, url, errorListener);
        setRetryPolicy(
                new DefaultRetryPolicy(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT));
        mListener = listener;
        mDecodeConfig = decodeConfig;
        mMaxWidth = maxWidth;
        mMaxHeight = maxHeight;
    }

可以看到,ImageRequest的构造函数接收六个参数,每个参数含义如下:

 url URL of the image 第一个参数就是图片的URL地址

listener Listener to receive the decoded bitmap第二个参数是图片请求成功的回调

maxWidth Maximum width to decode this bitmap to, or zero for none,maxHeight Maximum height to decode this bitmap to, or zero for none第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。

decodeConfig Format to decode the bitmap to第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。

errorListener Error listener, or null to ignore errors第六个参数是图片请求失败的回调,通常当请求失败时在ImageView中显示一张默认图片。


它的使用与StringRequest一模一样,代码如下:

RequestQueue mQueue = Volley.newRequestQueue(context);

ImageRequest imageRequest = new ImageRequest(
		"http://www.baidu.com/home/home.png",
		new Response.Listener<Bitmap>() {
			@Override
			public void onResponse(Bitmap response) {
				imageView.setImageBitmap(response);
			}
		}, 0, 0, Config.RGB_565, new Response.ErrorListener() {
			@Override
			public void onErrorResponse(VolleyError error) {
				imageView.setImageResource(R.drawable.default_image);
			}
		});

mQueue.add(imageRequest);


4ImageLoader

上述三中类型其父类都继承自Request。因此它们的用法非常相似,但是ImageLoader则不然,我们还是先来看一下类的定义:

public class ImageLoader
可以看到ImageLoader没继承任何类,因此它的用法与上述三种不同。

下面我们来看一下ImageLoader中一些重要的属性成员:

private final ImageCache mCache;

public interface ImageCache {
        public Bitmap getBitmap(String url);
        public void putBitmap(String url, Bitmap bitmap);
    }

可以看到在ImageLoader中存在一个 ImageCache成员,它被定义为ImageLoader的一个内部接口,顾名思义,ImageCache是用来缓存图片的,因此可知ImageLoader具备缓存图片的功能,这也是ImageLoader比ImageRequest高效的原因。通常使用缓存的话会用到LruCache这个类。


下面我们来看一下其构造函数:

public ImageLoader(RequestQueue queue, ImageCache imageCache) {
        mRequestQueue = queue;
        mCache = imageCache;
    }

其构造器包括两个参数,第一个为RequestQueue对象,第二个为 ImageCache对象。我们来看一下如何使用它:

RequestQueue mQueue = Volley.newRequestQueue(context);

public class BitmapCache implements ImageCache {

	private LruCache<String, Bitmap> mCache;

	public BitmapCache() {
		int maxSize = 10 * 1024 * 1024;
		mCache = new LruCache<String, Bitmap>(maxSize) {
			@Override
			protected int sizeOf(String key, Bitmap bitmap) {
				return bitmap.getRowBytes() * bitmap.getHeight();
			}
		};
	}

	@Override
	public Bitmap getBitmap(String url) {
		return mCache.get(url);
	}

	@Override
	public void putBitmap(String url, Bitmap bitmap) {
		mCache.put(url, bitmap);
	}

}
ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());

ImageListener listener = ImageLoader.getImageListener(imageView,
		R.drawable.default_image, R.drawable.failed_image);
imageLoader.get("http://www.baidu.com/index/logo.jpeg", listener);

可以看到总共包含大致四步(第二步创建一个缓存可以不用):

1. 创建一个RequestQueue对象。
2. 创建一个ImageLoader对象。(在这一步中如果要用到缓存,还需要创建一个缓存的类的实例)
3. 获取一个ImageListener对象。
4. 调用ImageLoader的get()方法加载网络上的图片。

在第三步中调用ImageLoader的getImageListener()方法能够获取到一个ImageListener对象,getImageListener()方法接收三个参数,第一个参数指定用于显示图片的ImageView控件,第二个参数指定加载图片的过程中显示的图片,第三个参数指定加载图片失败的情况下显示的图片。当第四部使用ImageLoader的get()方法加载网络上的图片后,ImageListener会自动将结果显示在ImageView控件上。

在第四步中get()方法接收两个参数,第一个参数就是图片的URL地址,第二个参数则是刚刚获取到的ImageListener对象。当然,如果你想对图片的大小进行限制,也可以使用get()方法的重载,指定图片允许的最大宽度和高度,如下所示:

imageLoader.get("http://www.baidu.com/index/logo.jpeg",
				listener, 200, 200);

可以看到在上述几种方式中首先都要创建一个RequestQueue,那是不是我们每次使用都得创建一个呢?其实不需要,我们全局保有一个即可。这时候自然想到使用Application了。我们可以在Application里面创建RequestQueue,然后提供一个getRequestQueue()对外暴露该RequestQueue。代码很简单,相信大家都会写。 

  以上就是关于Volley的基本用法,感谢大家能看到最后!






本文转载自:http://blog.csdn.net/htq__/article/details/51113774

共有 人打赏支持
htq

htq

粉丝 19
博文 67
码字总数 1007
作品 3
武汉
volley框架下发送和读取cookie

本文为原创,转载请注明出处,否则将依法追究版权 我们平时开发android应用都需要用到网络技术,通常采用http协议来发起请求并接受网络数据。android系统提供两种方式进行http通信:HttpURL...

刘小米 ⋅ 2014/12/29 ⋅ 11

Android Volley完全解析(一),初识Volley的基本用法

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482095 1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用...

mingxun ⋅ 2014/04/18 ⋅ 0

Volley 基本用法

GitHubDemo https://github.com/smanikandan14/Volley-demo#handling-error-codes Volley源码 https://github.com/mcxiaoke/android-volley Google IO2013网络框架Volley 演讲PDF http://do......

小强强强 ⋅ 2015/03/23 ⋅ 0

Android 中判断网络连接和GPS是否可用及HTTPCLIENT使用

大家知道Google支持和发布的Android移动操作系统,主要是为了使其迅速占领移动互联网的市场份额,所谓移动互联网当然也是互联网了,凡是涉及互联网的任何软件任何程序都少不了联网模块的开发...

xztelecomlcs ⋅ 2017/03/14 ⋅ 0

【Android】android Volley完全解析(一)

前言 Volley是一个由Google官方推出的网络通信库,它使得Android进行网络请求时更加方便、快速、健壮,同时对网络图片加载也提供了良好的支持。 不过HttpURLConnection和HttpClient的用法还是...

定陶黄公子 ⋅ 2016/12/13 ⋅ 0

浅谈——Android学习之路

电脑–推荐 Mac   首先声明我不是果粉,个人 Windows,Linux,Mac OX 系统均用过, 只能说 Windows 上面的开发工具简直难以恭维,尤其命令行超级难用,而 Linux 自己必须得花不少时间在折腾...

浮生侃侃 ⋅ 2016/04/21 ⋅ 0

Android Volley学习

开发android应用很多时候都要涉及网络操作,Android SDK中提供了HttpClient 和 HttpUrlConnection两种方式用来处理网络操作,但当应用比较复杂的时候需要我们编写大量的代码处理很多东西:图...

JeremyDai ⋅ 2016/05/05 ⋅ 0

个人视频发布汇总——教育改变人生

个人视频发布汇总——教育改变人生 本博文汇总我个人的视频集,视频以后会越来越多的,希望得到大家的支持 一.通往Android的神奇之旅 这也是我的第一个视频系列,目前也快更新完了 售价:免费...

刘桂林 ⋅ 2016/08/23 ⋅ 0

Volley 源码解析

本文为 Android 开源项目源码解析 中 Volley 部分 项目地址:Volley,分析的版本:35ce778,Demo 地址:Volley Demo 分析者:grumoon,校对者:huxian99、Trinea,校对状态:完成 1. 功能介绍...

程序袁_绪龙 ⋅ 2015/12/17 ⋅ 1

Android 开源项目推荐之「网络请求哪家强」

网络请求这个话题基本是所有 App 开发都会遇到的,这也难怪之前很多人留言让我写写网络请求到底该怎么选择,今天就来说说网络请求到底哪家强! 1 原则 本篇说的网络请求专指 http 请求,在选...

oschina ⋅ 2016/08/05 ⋅ 16

没有更多内容

加载失败,请刷新页面

加载更多

下一页

用ZBLOG2.3博客写读书笔记网站能创造今日头条的辉煌吗?

最近两年,著名的自媒体网站今日头条可以说是火得一塌糊涂,虽然从目前来看也遇到了一点瓶颈,毕竟发展到了一定的规模,继续增长就更加难了,但如今的今日头条规模和流量已经非常大了。 我们...

原创小博客 ⋅ 今天 ⋅ 0

MyBatis四大核心概念

本文讲解 MyBatis 四大核心概念(SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper)。 MyBatis 作为互联网数据库映射工具界的“上古神器”,训有四大“神兽”,谓之:Sql...

waylau ⋅ 今天 ⋅ 0

以太坊java开发包web3j简介

web3j(org.web3j)是Java版本的以太坊JSON RPC接口协议封装实现,如果需要将你的Java应用或安卓应用接入以太坊,或者希望用java开发一个钱包应用,那么用web3j就对了。 web3j的功能相当完整...

汇智网教程 ⋅ 今天 ⋅ 0

2个线程交替打印100以内的数字

重点提示: 线程的本质上只是一个壳子,真正的逻辑其实在“竞态条件”中。 举个例子,比如本题中的打印,那么在竞态条件中,我只需要一个方法即可; 假如我的需求是2个线程,一个+1,一个-1,...

Germmy ⋅ 今天 ⋅ 0

Springboot2 之 Spring Data Redis 实现消息队列——发布/订阅模式

一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式,这里利用redis消息“发布/订阅”来简单实现订阅者模式。 实现之前先过过 redis 发布订阅的一些基础概念和操...

Simonton ⋅ 今天 ⋅ 0

error:Could not find gradle

一.更新Android Studio后打开Project,报如下错误: Error: Could not find com.android.tools.build:gradle:2.2.1. Searched in the following locations: file:/D:/software/android/andro......

Yao--靠自己 ⋅ 昨天 ⋅ 0

Spring boot 项目打包及引入本地jar包

Spring Boot 项目打包以及引入本地Jar包 [TOC] 上篇文章提到 Maven 项目添加本地jar包的三种方式 ,本篇文章记录下在实际项目中的应用。 spring boot 打包方式 我们知道,传统应用可以将程序...

Os_yxguang ⋅ 昨天 ⋅ 0

常见数据结构(二)-树(二叉树,红黑树,B树)

本文介绍数据结构中几种常见的树:二分查找树,2-3树,红黑树,B树 写在前面 本文所有图片均截图自coursera上普林斯顿的课程《Algorithms, Part I》中的Slides 相关命题的证明可参考《算法(第...

浮躁的码农 ⋅ 昨天 ⋅ 0

android -------- 混淆打包报错 (warning - InnerClass ...)

最近做Android混淆打包遇到一些问题,Android Sdutio 3.1 版本打包的 错误如下: Android studio warning - InnerClass annotations are missing corresponding EnclosingMember annotation......

切切歆语 ⋅ 昨天 ⋅ 0

eclipse酷炫大法之设置主题、皮肤

eclipse酷炫大法 目前两款不错的eclipse 1.系统设置 Window->Preferences->General->Appearance 2.Eclipse Marketplace下载【推荐】 Help->Eclipse Marketplace->搜索‘theme’进行安装 比如......

anlve ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部