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

来源:互联网 发布:云南广电网络oa 编辑:程序博客网 时间:2024/06/11 04:15

首先,结合开发文档的第一篇 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-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.                    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解决乱序问题。

0 0
原创粉丝点击