您的位置:首页 > 其它

结合开发文档分析volley(一)

2016-07-23 19:13 330 查看
首先,结合开发文档的第一篇 Sending a Simple Request来分析vollry。

http://wear.techbrood.com/training/volley/simple.html

1.添加网络权限

android.permission.INTERNET

2.newRequestQueue的使用

RequestQueue管理网络操作和读写缓冲的工作线程和解析结果。

RequestQueue queue = Volley.newRequestQueue(this);


3.传送Request

首先创建Request,以StringRequest为例。

StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});


传送Request

queue.add(stringRequest);


在创建了RequestQueue的实例对象后,后台就跑着两个线程—–one cache processing thread and a pool of network dispatch threads(一个缓冲线程和一个网络线程池).当你把request对象加到队列后,它首先被缓冲线程执行,如果request能在保存的缓冲中得到处理,那么就将缓冲的结果传送回主线程,如果request没能在缓冲中得到处理,它将会放置在网络作业队列中,然后网络线程池对其进行处理,最后,将response写入缓冲,然后把简析的response传送回主线程。



上面文字描述的图示。

然后,接下来用源码解释图示。

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;


这是add的核心代码。它主要是先判断有没有一个和add函数的传入的request一样的request,如果有,把它加入stagedRequests 等待处理,打印出“这个request正在被执行”的log。如果没有,那么就将这个request加入mCacheQueue,交给缓冲线程去执行。这也验证了,前面说过的:add后,先把request交给缓冲线程执行,如果缓冲线程没有执行,在交给网络线程池执行。

一直在说缓冲线程和网络线程,来看一看它们的代码实现。缓冲线程的类名是CacheDispatcher,网络线程的类名是NetworkDispatcher。接下来在依次看它们的run方法。

CacheDispatcher的run方法体:结合前面说过的缓冲线程处理request的步骤来看源码,看是不是这样的。

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();

Request<?> request;
while (true) {
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
// Take a request from the queue.
request = mCacheQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
try {
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-pars
4000
ed");

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.
final Request<?> finalRequest = request;
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(finalRequest);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
}
}
}


NetworkDispatcher的run方法体:结合前面说过的网络线程处理request的步骤来看源码,看是不是这样的。

public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request<?> request;
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
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;
}

addTrafficStatsTag(request);

// Perform the network request.
NetworkResponse networkResponse = mNetwork.performRequest(request);
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);
request.addMarker("network-cache-written");
}

// Post the response back.
request.markDelivered();
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
VolleyError volleyError = new VolleyError(e);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
mDelivery.postError(request, volleyError);
}
}
}


4.取消Request

可以调用cancel函数取消request。

public void cancel() {
mCanceled = true;
}


它就是重置了一个标志位。这个标志位在哪发挥作用?

①在NetworkDispatcher的run方法体中,在执行访问网络操作之前。

if (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}


② 在传送解析了的networkResponse时。(前面说到的简析response也是指简析networkResponse)

if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}


这个可以用在瀑布流解决图片乱序问题,之后会写一个小程序来用cancel解决乱序问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  volley