Volley框架浅析
Posted 劲火星空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Volley框架浅析相关的知识,希望对你有一定的参考价值。
一、概念
什么是Volley
开发android应用很多时候都要涉及网络操作,Android SDK中提供了HttpClient 和 HttpUrlConnection两种方式用来处理网络操作,但当应用比较复杂的时候需要我们编写大量的代码处理很多东西:图像缓存,请求的调度等等;
而Volley框架就是为解决这些而生的,它与2013年Google I/O大会上被提出:使得Android应用网络操作更方便更快捷;抽象了底层Http Client等实现的细节,让开发者更专注与产生RESTful Request。另外,Volley在不同的线程上异步执行所有请求而避免了阻塞主线程。
二、特点
如下是Volley框架的内部实现原理图,蓝色是主线程,黄色是缓存线程,绿色是网络线程
- 自动调度网络请求
- 多个并发的网络连接
- 通过使用标准的HTTP缓存机制保持磁盘和内存响应的一致
- 支持请求优先级
- 支持取消请求的强大API,可以取消单个请求或多个
- 易于定制
- 健壮性:便于正确的更新UI和获取数据
- 包含调试和追踪工具
三、使用
1. 获得String数据
volleybt.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//新建请求队列
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
//新建请求
String url = "https://www.baidu.com/?tn=sitehao123_15";
StringRequest request = new StringRequest(url, new Response.Listener<String>()
@Override
public void onResponse(String s)
volleytext.setText(s);
, new Response.ErrorListener()
@Override
public void onErrorResponse(VolleyError volleyError)
volleytext.setText("加载失败"+volleyError);
);
requestQueue.add(request);
);
2. 获得json数据
json_bt.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
// 1 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
// 2 创建一个请求
String url = "http://api.m.mtime.cn/PageSubArea/TrailerList.api";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>()
@Override
public void onResponse(JSONObject jsonObject)
volleytext.setText(jsonObject.toString());
, new Response.ErrorListener()
@Override
public void onErrorResponse(VolleyError volleyError)
volleytext.setText("请求失败" + volleyError);
);
// 3 将创建的请求添加到请求队列中
requestQueue.add(jsonObjectRequest);
);
3. post获得String数据
post_bt.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
// 1 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
// 2 创建一个post请求
String url = "http://api.m.mtime.cn/PageSubArea/TrailerList.api";
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>()
@Override
public void onResponse(String s)
volleytext.setText(s);
, new Response.ErrorListener()
@Override
public void onErrorResponse(VolleyError volleyError)
volleytext.setText("请求失败" + volleyError);
)
;
// 3 将post请求添加到队列中
requestQueue.add(stringRequest);
);
4. 自定义获得xml数据
xml_bt.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
// 1 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
XMLRequest xmlRequest = new XMLRequest(
"http://flash.weather.com.cn/wmaps/xml/china.xml",
new Response.Listener<XmlPullParser>()
@Override
public void onResponse(XmlPullParser response)
try
int eventType = response.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT)
switch (eventType)
case XmlPullParser.START_TAG:
String nodeName = response.getName();
if ("city".equals(nodeName))
String pName = response.getAttributeValue(0);
Log.d("TAG", "pName is " + pName);
break;
eventType = response.next();
catch (XmlPullParserException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
, new Response.ErrorListener()
@Override
public void onErrorResponse(VolleyError error)
Log.e("TAG", error.getMessage(), error);
);
requestQueue.add(xmlRequest);
);
需要重新一个xmlRequest继承Request
public class XMLRequest extends Request<XmlPullParser>
private final Response.Listener<XmlPullParser> mListener;
public XMLRequest(int method, String url, Response.Listener<XmlPullParser> listener,
Response.ErrorListener errorListener)
super(method, url, errorListener);
mListener = listener;
public XMLRequest(String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener)
this(Method.GET, url, listener, errorListener);
@Override
protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response)
try
String xmlString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlString));
return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
catch (UnsupportedEncodingException e)
return Response.error(new ParseError(e));
catch (XmlPullParserException e)
return Response.error(new ParseError(e));
@Override
protected void deliverResponse(XmlPullParser response)
mListener.onResponse(response);
5. 自定义获得Gson解析后的数据
gson_bt.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(
"http://www.weather.com.cn/data/sk/101010100.html", Weather.class,
new Response.Listener<Weather>()
@Override
public void onResponse(Weather weather)
WeatherInfo weatherInfo = weather.getWeatherinfo();
Log.d("TAG", "city is " + weatherInfo.getCity());
Log.d("TAG", "temp is " + weatherInfo.getTemp());
Log.d("TAG", "time is " + weatherInfo.getTime());
, new Response.ErrorListener()
@Override
public void onErrorResponse(VolleyError error)
Log.e("TAG", error.getMessage(), error);
);
requestQueue.add(gsonRequest);
);
同样需要定义一个GsonRequest继承Request
public class GsonRequest<T> extends Request<T>
private final Response.Listener<T> mListener;
private Gson mGson;
private Class<T> mClass;
public GsonRequest(int method, String url, Class<T> clazz, Response.Listener<T> listener,
Response.ErrorListener errorListener)
super(method, url, errorListener);
mGson = new Gson();
mClass = clazz;
mListener = listener;
public GsonRequest(String url, Class<T> clazz, Response.Listener<T> listener,
Response.ErrorListener errorListener)
this(Method.GET, url, clazz, listener, errorListener);
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response)
try
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(mGson.fromJson(jsonString, mClass),
HttpHeaderParser.parseCacheHeaders(response));
catch (UnsupportedEncodingException e)
return Response.error(new ParseError(e));
@Override
protected void deliverResponse(T response)
mListener.onResponse(response);
//用于解析的类
class Weather
private WeatherInfo weatherinfo;
public WeatherInfo getWeatherinfo()
return weatherinfo;
public void setWeatherinfo(WeatherInfo weatherinfo)
this.weatherinfo = weatherinfo;
还需要一个WeatherInfo类来解析Gson
public class WeatherInfo
private String city;
private String temp;
private String time;
public String getCity()
return city;
public void setCity(String city)
this.city = city;
public String getTemp()
return temp;
public void setTemp(String temp)
this.temp = temp;
public String getTime()
return time;
public void setTime(String time)
this.time = time;
四、原理
首先来梳理一下整体的流程,先建立也队列,根据不同的系统版本建立不同的网络初始化,接下来在这个队列 中建立一个缓存进程和四个网络进程,一共是五个进程,然后在就是往这个队列中添加任务来。如果得到的请求有缓存资源就可以进行通过缓存线程执行任务了,如果没有缓存就加入到网路线程任务中,处理完成后将response发送出去,我们在回调函数中就可以得到结果了。
(一)队列创建
(1)网络的选择,是选择HttpStack还是HttpClientStack
public static RequestQueue newRequestQueue(Context context, HttpStack stack)
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
catch (NameNotFoundException e)
if (stack == null)
if (Build.VERSION.SDK_INT >= 9)
stack = new HurlStack();
else
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
Network network = new BasicNetwork(stack);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
(2)建立一个缓存线程和四个网络线程
public void start()
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++)
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
(二)增加请求
(1)加入队列中
public <T> Request<T> add(Request<T> request)
// Tag the request as belonging to this queue and add it to the set of current requests.
request.setRequestQueue(this);
synchronized (mCurrentRequests)
mCurrentRequests.add(request);
// Process requests in the order they are added.
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// If the request is uncacheable, skip the cache queue and go straight to the network.
if (!request.shouldCache())
mNetworkQueue.add(request);
return request;
// Insert request into stage if there's already a request with the same cache key in flight.
synchronized (mWaitingRequests)
String cacheKey = request.getCacheKey();
if (mWaitingRequests.containsKey(cacheKey))
// There is already a request in flight. Queue up.
Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null)
stagedRequests = new LinkedList<Request<?>>();
stagedRequests.add(request);
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG)
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
else
// Insert 'null' queue for this cacheKey, indicating there is now a request in
// flight.
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
return request;
(2)通过while循环的方式进行相应,如果缓存为空就加入到网络线程中
public class CacheDispatcher extends Thread
……
@Override
public void run()
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Make a blocking call to initialize the cache.
mCache.initialize();
while (true)
try
// Get a request from the cache triage queue, blocking until
// at least one is available.
final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take");
// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled())
request.finish("cache-discard-canceled");
continue;
// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null)
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);
continue;
// If it is completely expired, just send it to the network.
if (entry.isExpired())
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded())
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
else
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
mDelivery.postResponse(request, response, new Runnable()
@Override
public void run()
try
mNetworkQueue.put(request);
catch (InterruptedException e)
// Not much we can do about this.
);
catch (InterruptedException e)
// We may have been interrupted because it was time to quit.
if (mQuit)
return;
continue;
(3)最后进行事件的分发
尊重作者,尊重原创,参考文章:
http://blog.csdn.net/guolin_blog/article/details/17656437
http://www.cnblogs.com/zyw-205520/p/4950357.html
以上是关于Volley框架浅析的主要内容,如果未能解决你的问题,请参考以下文章