12.网络框架volley
来源:互联网 发布:安徽文华软件 编辑:程序博客网 时间:2024/06/07 23:42
转载请标明出处:
http://blog.csdn.net/yujun411522/article/details/46226087
本文出自:【yujun411522的博客】
在android开发中使用网络的场景很多,绝大部分都是http方式。就算是采用上面的httpurlconnection和httpclient有时仍然是会稍显麻烦,所以一个新的网络通信框架应运而生:volley。它的使用场景是数据量不大但是访问通信很频繁的网络操作,我们绝大部分的操作也是如此,比如用app浏览新闻等。它对大数据量的操作比如下载文件支持的不好。
12.1常见用法
简要介绍一个常见的用法。
1 获得一个RequestQueue:RequestQueue mQueue = Volley.newRequestQueue(context);这里是一个请求队列,缓存所有的http请求。使用时只需要将http请求加入这个队列即可。内部实现很高效,后面分析。
2 创建http请求,以StringRequest为例子:
StringRequest stringRequest = new StringRequest("http://www.baidu.com",new Response.Listener<String>(){
//override
public void onResponse(String response){
//成功获取http数据
Log.d("tag",response);
}
},new Response.ErrorListener(){
//override
public void onErrorResponse(VolleyError error){
//获取http数据失败
Log.d("tag",error.getMessage());
}
});
如果使用post请求,可以重写父类request的getParam方法,不再赘述。
请求方式还可以是Json数据,框架已经封装好了,我们来看:JsonRequest是一个抽象类,使用的话使用两个子类:JsonObjectRequest和JsonArrayRequest。以JsonObjectRequest为例子
JsonObjectRequest request = new JsonObjectRequest(url,new Response.Listener<JSONObject>(){
public void onResonse(JSONObject response){
}
},new Response.ErrorListener(){
public void onErrorResponse(VolleyError error){
//
}
});
volley 还可以请求网络图片,有ImageRequest,ImageLoader,和NetworkImageView(控件形式),不再赘述。
3 将http请求加入到requestqueue中:mQueue.add(stringRequest);之后就会自动的进行网络请求。
总结起来就是:1.构造一个RequestQueue,2.构造一个http请求,3.然后加入到requestqueue中即可。
12.2自定义request
Volley框架里面提供请求方式有限,我们也可以定义自己的请求
先看StringRequest类:继承Request
重要成员变量:private final Listener<String> mListner;
重要方法:
1 protected void deliverResponse(String response){
//就是调用了定义时的Listener.onResponse()方法。
//此方法在ExecutorDelivery中会执行
mListener.onResponse(response);
}
2 protected Response<String> parseNetworkResponse(NetworkResponse response){
//将返回数据解析成以Response<String>类型.
String parsed;
try{
parsed = new String(response.data,HttpHeaderParser.parseCharset(response.header));
}
catch(UnsuppoertedEncodingException e){
parsed = new String(response.data);
}
//返回Response<String>类型
return Response.success(parsed,HttpHeaderParser.parseCacheHeaders(response));
}
这里我们实现一个解析xml文件的自定义request,解析器选择XmlPullParser
重点实现Response<XmlPullParser> parserNetworkResponse()方法
protected Response<XmlPullParser> parserNetworkResponse(NetworkResponse response){
String xmlString;
try{
xmlString = new String(response.data,HttpHeaderParser.parseCharset(response.header));//先将原始Response转化成string类型,便于解析
XmlPullParser parser = XmlParserFactory.newInstance().newPullParser();//创建XmlPullParser解析xml文件
parser.setInput(new StringReader(xmlString));//设置XmlPullParser的解析内容
return Response.success(parser,parsed,HttpHeaderParser.parseCacheHeaders(response));//返回一个Response<XmlPullParser> 对象
}
catch(){
}
}
然后在Listener中重写onResponse方法通过xmlPullparser解析xml文件:
mXmlRequest = new XmlRequest(
"http://flash.weather.com.cn/wmaps/xml/china.xml",
new Response.Listener<XmlPullParser>() {
public void onResponse(XmlPullParser response) {//解析xml文件
try {
int eventType = response.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
StringBuilder builder = new StringBuilder();
if (eventType == XmlPullParser.START_TAG) {
String tagName = response.getName();
if (tagName.equals("city")) {
builder.append("city<");
int count = response.getAttributeCount();
for (int i = 0; i < count; i++) {
builder.append(" "+response.getAttributeName(i)+ "="+ response.getAttributeValue(i));
}
}
builder.append("\n");
}
Log.d("XmlRequest", builder.toString());
eventType = response.next();
}
} catch (Exception e) {
Log.d("XmlRequest", e.getMessage());
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("XmlRequest", error.getMessage());
}
"http://flash.weather.com.cn/wmaps/xml/china.xml",
new Response.Listener<XmlPullParser>() {
public void onResponse(XmlPullParser response) {//解析xml文件
try {
int eventType = response.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
StringBuilder builder = new StringBuilder();
if (eventType == XmlPullParser.START_TAG) {
String tagName = response.getName();
if (tagName.equals("city")) {
builder.append("city<");
int count = response.getAttributeCount();
for (int i = 0; i < count; i++) {
builder.append(" "+response.getAttributeName(i)+ "="+ response.getAttributeValue(i));
}
}
builder.append("\n");
}
Log.d("XmlRequest", builder.toString());
eventType = response.next();
}
} catch (Exception e) {
Log.d("XmlRequest", e.getMessage());
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("XmlRequest", error.getMessage());
}
});
12.3 源码分析:
这是官网给出的操作流程:
volley总体设计图:
简单介绍其中的一些类
Volley:对外暴露的API,通过newRequestQueue来创建一个requestQueue。
Request:一个http请求抽象类,可以使用子类StringRequest,JsonRequest等等,还可以自定义request。
RequestQueue:http请求队列,里面有一个cacheDispatcher用于处理可以缓存的请求,一个networkdispatcher数组,用户处理网络访问的请求。一个responseDelivery用户返回response结果。
CacheDispatcher:线程,处理可以缓存的请求。启动之后不断从mCacheQueue中取出request。如果没有canceled,没有过期,且命中的话直接解析该网络结果,否则将该request加入到mNetworkQueue中处理。
NetworkDispatcher:线程,处理进行网络请求。其中之后从mNetworkQueue中取出request,请求http结束之后将结果responsedelivery进行处理。有必要时对其进行缓存。
ResponseDelivery:一个接口、用于处理请求响应的。
ExecutorDelivery:ResponseDelivery的实现类。
HttpStack:处理http请求,使用的基于HttpURLConnection的HurlStack和基于HttpClient的HttpClientStack。
NetWork:一个处理请求的接口,有实现类BasicNetwork
Cache:缓存请求结果的。使用的DiskBasedCache。如果请求的http在cache中有,直接取出结果使用。
下面看具体的代码
Volley.java
重要的就两个重载方法
public static RequestQueue newRequestQueue(Context){}
public static RequestQueue newRequestQueue(Context,HttpStack){}
在构造时如果不提供HttpStack,系统默认按照自己的方式生成,还需要使用netWork将stack包装起来:
public static RequestQueuenewRequestQueue(Context context, HttpStack stack) {
//....设置缓存文件目录
//设置HttpStack API>=9,HulStack,API,9 HttpClientStack
//在 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。
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( newDiskBasedCache(cacheDir),network);
queue.start();
return queue;
}
再看Request.java以及其子类。
重要的方法:
//子类实现此方法,解析原始的response返回一个合适的Respose type(类型可以是String,JSONObject,或者自定义的XMLPullParser)
abstract protected Response<T> parseNetworkResponse(NetworkResponse response):
/**
* Subclasses must implement this toparse the raw network response andreturn an appropriate response type. This method will be
* called from a worker thread. The response will not be delivered if you return null.
* @param response Response from the network
* @return The parsed response, or null in the case of an error
*/
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);//子类要实现这个方法,主要工作就是将原始network Response转换成一个合适类型(String,JSON,XML)的Response。
* called from a worker thread. The response will not be delivered if you return null.
* @param response Response from the network
* @return The parsed response, or null in the case of an error
*/
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);//子类要实现这个方法,主要工作就是将原始network Response转换成一个合适类型(String,JSON,XML)的Response。
//子类中实现此方法,将已经解析好的response发送给他们的监听器。
abstract protected void deliverResponse(T response);
/**
* Subclasses must implement this to perform delivery of the parsed response to theirlisteners. The given response is guaranteed to
* be non-null; responses that fail to parse are not delivered.
* @param response The parsed response returned by
* {@link #parseNetworkResponse(NetworkResponse)}
*/
abstract protected void deliverResponse(T response);
* Subclasses must implement this to perform delivery of the parsed response to theirlisteners. The given response is guaranteed to
* be non-null; responses that fail to parse are not delivered.
* @param response The parsed response returned by
* {@link #parseNetworkResponse(NetworkResponse)}
*/
abstract protected void deliverResponse(T response);
再看RequestQueue.java
重要成员变量:
1 两个基于优先级的阻塞队列:mCacheQueue,mNetworkQueue。mCacheQueue可以cache的队列,mNetworkQueue进行网络请求的队列
/** The cache triage queue. */
private final PriorityBlockingQueue<Request> mCacheQueue = new PriorityBlockingQueue<Request>();
/** The queue of requests that are actually going out to the network. */
private final PriorityBlockingQueue<Request> mNetworkQueue = new PriorityBlockingQueue<Request>();
2 mWaitingRequests:正在等待的请求集合,如果有相同url的请求,将生成一个该url的队列,加入到此map中。
private final Map<String, Queue<Request>> mWaitingRequests = new HashMap<String, Queue<Request>>();
3 mCurrentRequests:正在进行处理的request集合,如果在任何一个queue中等待或者被任意一个Dispatcher处理的请求都在此set中。
private final Set<Request> mCurrentRequests = new HashSet<Request>();
4 mDispatchers:用于处理mNetworkQueue的线程数组
private NetworkDispatcher[] mDispatchers;
5 mCacheDispatcher:用户处理mCacheQueue的线程
private CacheDispatcher mCacheDispatcher;
重要方法
1 start ,之前Volley.newRequestQueue方法中调用了此方法
/**
* Starts the dispatchers in this queue.
*/
public void start() {
stop(); //停止mCacheDispatcher和mDispatchers线程
// 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++) {
//mDispatchers. length默认值是4
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue , mNetwork ,mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
所以这里一共开始了五个线程
2 add方法,就是我们在创建请求之后添加到RequestQueue中。
总体流程如下
上代码:
public Request add(Request 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()) {
//不允许cache,直接请求http网络,返回
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 和mCacheQueue中。
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
}
return request;
}
}
3 finish方法
void finish(Request request) {
// Remove from the set of requests currently being processed.
synchronized (mCurrentRequests ) {
mCurrentRequests.remove(request);
}
if (request.shouldCache()) {
synchronized (mWaitingRequests ) {
String cacheKey = request.getCacheKey();
Queue<Request> waitingRequests =mWaitingRequests.remove(cacheKey);
if (waitingRequests != null) {
mCacheQueue.addAll(waitingRequests);
}
}
}
}
再看CacheDispatcher.java
线程类,重要的就看run方法的流程:
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();//mCacheQueue取出来一个request
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;//request结束,继续执行while
}
// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {//cache 没有命中
request.addMarker( "cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);//没有命中,加入到mNetworkQueue
continue;//request结束,继续执行while
}
// 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);//命中但是结果过期,加入到mNetworkQueue
continue;//request结束,继续执行while
}
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker( "cache-hit");
//如果cache命中,则构造一个NetworkResponse并解析成Response<?>类型
Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry. data, entry.responseHeaders));//cache命中,
request.addMarker( "cache-hit-parsed");
//直接传输响应结果
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
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;
}
}
}
还有一个线程类NetWorkDispatcher.java
run方法流程:
上代码:
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request request;
while (true ) {
try {
// Take a request from the queue.
request = mQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit ) {
return;
}
continue;
}
try {
request.addMarker( "network-queue-take");
// If the request was cancelled already, do not perform the
// network request.
if (request.isCanceled()) {
request.finish("network-discard-cancelled" );
continue;
}
// Tag the request (if API >= 14)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH ) {
TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
}
// Perform the network request.
NetworkResponse networkResponse = mNetwork.performRequest(request);//进行http请求,并返回一个NetworkResponse 对象
request.addMarker("network-http-complete" );
// If the server returned 304 AND we delivered a response already,
// we're done -- don't deliver a second identical response.
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish( "not-modified");
continue;
}
// Parse the response here on the worker thread.
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete" );
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
if (request.shouldCache() && response.cacheEntry != null ) {
mCache.put(request.getCacheKey(), response.cacheEntry);//加入到cache中,下次请求相同http直接可以从cache中取出来
request.addMarker("network-cache-written" );
}
// Post the response back.
request.markDelivered();
mDelivery.postResponse(request, response);//传输Response结果
} catch (VolleyError volleyError) {
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog. e(e, "Unhandled exception %s", e.toString());
mDelivery.postError(request, new VolleyError(e));
}
}
}
再看如何分派request的接口ResponseDelivery.java以及它的实现类ExecutorDelivery.java
public interface ResponseDelivery {
/**
* Parses a response from the network or cache and delivers it.
*/
public void postResponse(Request<?> request, Response<?> response);
/**
* Parses a response from the network or cache and delivers it. The provided
* Runnable will be executed after delivery.
*/
public void postResponse(Request<?> request, Response<?> response, Runnable runnable);
/**
* Posts an error for the given request.
*/
public void postError(Request<?> request, VolleyError error);
}
实现类ExecutorDelivery.java
里面定义了一个内部私有类ResponseDeliveryRunnable
private class ResponseDeliveryRunnable implements Runnable {
@Override
public void run() {
// If this request has canceled, finish it and don't deliver.
if (mRequest .isCanceled()) {
mRequest.finish( "canceled-at-delivery" );
return ;
}
// Deliver a normal response or error, depending.
if (mResponse .isSuccess()) {
//如果request请求成功,执行该request的deliveryResponse方法,也就是我们在实例化request时的Response.Listener<T>
mRequest .deliverResponse(mResponse .result );
} else {
//如果request请求失败,执行该request的deliveryError方法,也就是我们在实例化request时的new Response.ErrorListener()
mRequest.deliverError( mResponse .error );
}
// If this is an intermediate response, add a marker, otherwise we're done
// and the request can be finished.
....
}
}
参考:http://codekk.com/open-source-project-analysis/detail/Android/grumoon/Volley%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90
0 0
- 12.网络框架volley
- 网络请求框架---Volley
- 网络通信框架Volley
- Volley网络框架详解
- Android网络框架Volley
- Android网络框架Volley
- Android网络框架Volley
- Andoid 网络框架--Volley
- 网络框架Volley
- android 网络框架 volley
- android Volley网络框架
- Volley网络请求框架
- Android网络框架Volley
- 网络请求框架---Volley
- 网络请求框架-Volley
- Android网络框架Volley
- volley网络框架
- Volley-----网络请求框架
- Drill 大数据高级查询工具
- Android Broadcast 和 BroadcastReceiver的自定义权限使用
- 简单实现带界面的一对一聊天
- 11.http怎么加入超时和代理
- SQL SERVER中强制类型转换cast和convert的区别
- 12.网络框架volley
- 13.ListView和GridView
- 第一次进入CSDN,或许新的生活就要开始了
- extjs的页面
- java基础篇——多线程
- 14.OOM内存溢出
- 《设计模式》第二章
- ActionScript 3.0 学习(一) Array、Vector以及Object学习
- 带缺口的圆环CSS3 Loading动画