【安卓网络请求开源框架Volley源码解析系列】初识Volley及其基本用法
在安卓中当涉及到网络请求时,我们通常使用的是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的基本用法,感谢大家能看到最后!
【安卓网络请求开源框架Volley源码解析系列】初识Volley及其基本用法的更多相关文章
- 【安卓网络请求开源框架Volley源码解析系列】定制自己的Request请求及Volley框架源码剖析
通过前面的学习我们已经掌握了Volley的基本用法,没看过的建议大家先去阅读我的博文[安卓网络请求开源框架Volley源码解析系列]初识Volley及其基本用法.如StringRequest用来请求一 ...
- Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析
Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们 ...
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- # Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析#
Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析 Volley源码一共40多个类和接口.除去一些工具类的实现,核心代码只有20多个类.所以相对来说分析起来没有那么吃力.但是要想分析透 ...
- Volley源码解析(三) 有缓存机制的情况走缓存请求的源码分析
Volley源码解析(三) 有缓存机制的情况走缓存请求的源码分析 Volley之所以高效好用,一个在于请求重试策略,一个就在于请求结果缓存. 通过上一篇文章http://www.cnblogs.com ...
- Volley 源码解析
Volley 源码解析 1. 功能介绍 1.1. Volley Volley 是 Google 推出的 Android 异步网络请求框架和图片加载框架.在 Google I/O 2013 大会上发布. ...
- Spring源码解析系列汇总
相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...
随机推荐
- hdu 5533(几何水)
Input The first line contains a integer T indicating the total number of test cases. Each test case ...
- bzoj1071[SCOI2007]组队
1071: [SCOI2007]组队 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 2472 Solved: 792[Submit][Status][ ...
- ubuntu linux c学习笔记----共享内存(shmget,shmat,shmdt,shmctl)
shmget int shmget(key_t key, size_t size, int flag); key: 标识符的规则 size:共享存储段的字节数 flag:读写的权限 返回值:成功返回共 ...
- mysql获取某个表的所有字段名
http://www.netingcn.com/mysql-column-name.html mysql安装成功后可以看到已经存在mysql.information_schema和test这个几个数据 ...
- 好用的jquery.animateNumber.js数字动画插件
在做公司的运营报告页面时,有一个数字累计增加的动画效果,一开始,毫无头绪,不知如何下手,于是上网查资料,发现大多都是用的插件来实现的,那么今天,我也来用插件jquery.animateNumber.j ...
- 安装插件出现eclipse An internal error occurred during: "Installing Software". xxxxxxxxx
就是你自己本来就有那个插件了 百度怎么删吧.... 看一下我这个文章 强烈建议本地安装的时候用第四种安装 http://www.cnblogs.com/ydymz/articles/7203260.h ...
- Ajax相关——get请求和post请求的区别
一.完整的URL由以下几部分组成: scheme:通信协议,常用的有:http/ftp. host:主机,服务器(计算机)域名或IP地址 port:端口,整数,可选,省略时使用默认端口,http的默认 ...
- JavaScript正则表达式模式匹配(4)——使用exec返回数组、捕获性分组和非捕获性分组、嵌套分组
使用exec返回数组 var pattern=/^[a-z]+\s[0-9]{4}$/; var str='google 2012'; alert(pattern.exec(str)); //返回一个 ...
- Cookie&Seesion会话 共享数据 工作流程 持久化 Servlet三个作用域 会话机制
Day37 Cookie&Seesion会话 1.1.1 什么是cookie 当用户通过浏览器访问Web服务器时,服务器会给客户端发送一些信息,这些信息都保存在Cookie中.这样,当该浏览器 ...
- opencv之人脸识别
最近在做一个类似于智能广告投放的项目,简单思路是利用opencv获取摄像头图像,然后调用接口或利用其他一些离线模型进行人脸属性识别,进而投放广告.本篇先简单介绍利用opecv进行人脸识别. # -*- ...