zoukankan      html  css  js  c++  java
  • Volley源码分析(四)NetWork与ResponseDelivery工作原理

    这篇文章主要分析网络请求和结果交付的过程。

    NetWork工作原理

    之前已经说到通过mNetWork.performRequest()方法来得到NetResponse,看一下该方法具体的执行流程,performRequest是一个接口方法,真正实现该方法以及被调用的是BasicNetWork,其具体的performRequest代码如下:

     @Override
        public NetworkResponse performRequest(Request<?> request) throws VolleyError {
            long requestStart = SystemClock.elapsedRealtime();
            while (true) {
                HttpResponse httpResponse = null;
                byte[] responseContents = null;
                Map<String, String> responseHeaders = Collections.emptyMap();
                try {
                    // Gather headers.
                    Map<String, String> headers = new HashMap<String, String>();
                    addCacheHeaders(headers, request.getCacheEntry());
                    httpResponse = mHttpStack.performRequest(request, headers);
                    StatusLine statusLine = httpResponse.getStatusLine();
                    int statusCode = statusLine.getStatusCode();
    
                    responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                    // Handle cache validation.
                    if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
    
                        Entry entry = request.getCacheEntry();
                        if (entry == null) {
                            return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
                                    responseHeaders, true,
                                    SystemClock.elapsedRealtime() - requestStart);
                        }
    
                        // A HTTP 304 response does not have all header fields. We
                        // have to use the header fields from the cache entry plus
                        // the new ones from the response.
                        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
                        entry.responseHeaders.putAll(responseHeaders);
                        return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
                                entry.responseHeaders, true,
                                SystemClock.elapsedRealtime() - requestStart);
                    }
    
                    // Some responses such as 204s do not have content.  We must check.
                    if (httpResponse.getEntity() != null) {
                      responseContents = entityToBytes(httpResponse.getEntity());
                    } else {
                      // Add 0 byte response as a way of honestly representing a
                      // no-content request.
                      responseContents = new byte[0];
                    }
    
                    // if the request is slow, log it.
                    long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                    logSlowRequests(requestLifetime, request, responseContents, statusLine);
    
                    if (statusCode < 200 || statusCode > 299) {
                        throw new IOException();
                    }
                    return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
                            SystemClock.elapsedRealtime() - requestStart);
                } catch (SocketTimeoutException e) {
                    attemptRetryOnException("socket", request, new TimeoutError());
                } catch (ConnectTimeoutException e) {
                    attemptRetryOnException("connection", request, new TimeoutError());
                } catch (MalformedURLException e) {
                    throw new RuntimeException("Bad URL " + request.getUrl(), e);
                } catch (IOException e) {
                    int statusCode;
                    if (httpResponse != null) {
                        statusCode = httpResponse.getStatusLine().getStatusCode();
                    } else {
                        throw new NoConnectionError(e);
                    }
                    VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
                    NetworkResponse networkResponse;
                    if (responseContents != null) {
                        networkResponse = new NetworkResponse(statusCode, responseContents,
                                responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                        if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
                                statusCode == HttpStatus.SC_FORBIDDEN) {
                            attemptRetryOnException("auth",
                                    request, new AuthFailureError(networkResponse));
                        } else if (statusCode >= 400 && statusCode <= 499) {
                            // Don't retry other client errors.
                            throw new ClientError(networkResponse);
                        } else if (statusCode >= 500 && statusCode <= 599) {
                            if (request.shouldRetryServerErrors()) {
                                attemptRetryOnException("server",
                                        request, new ServerError(networkResponse));
                            } else {
                                throw new ServerError(networkResponse);
                            }
                        } else {
                            // 3xx? No reason to retry.
                            throw new ServerError(networkResponse);
                        }
                    } else {
                        attemptRetryOnException("network", request, new NetworkError());
                    }
                }
            }
        }
    
    
    

    上述代码可以看出,真正进行网络请求还是HttpStack.performRequest,在请求结束以后,对返回的状态码进行封装,这里主要说一下304状态码,该状态码,由于只返回header,不返回body,因此body需要从以前缓存的entity中取出body。而HttpStack的两个实现类一个是HttpClientStack,另一个是HurlStack,他们也是直接调用Java自带的http请求方法来得到response。
    下面要看的是NetWorkResponse的封装

        public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
                boolean notModified, long networkTimeMs) {
            this.statusCode = statusCode;
            this.data = data;
            this.headers = headers;
            this.notModified = notModified;
            this.networkTimeMs = networkTimeMs;
        }
    
    

    这就是全部的NetWorkResponse的封装,封装的目的是为了对response进行交付。

    ResponseDelivery工作原理

    ResponseDelivery是一个接口,其定义了3个方法,2个传递response的重载方法与一个传递error方法

     /**
         * Parses a response from the network or cache and delivers it.
         */
        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.
         */
        void postResponse(Request<?> request, Response<?> response, Runnable runnable);
    
        /**
         * Posts an error for the given request.
         */
        void postError(Request<?> request, VolleyError error);
    
    

    其实现类ExecutorDelivery是真正执行的功能类。其内部非常简单,代码如下:

    public class ExecutorDelivery implements ResponseDelivery {
        /** Used for posting responses, typically to the main thread. */
        private final Executor mResponsePoster;
    
        /**
         * Creates a new response delivery interface.
         * @param handler {@link Handler} to post responses on
         */
        public ExecutorDelivery(final Handler handler) {
            // Make an Executor that just wraps the handler.
            mResponsePoster = new Executor() {
                @Override
                public void execute(Runnable command) {
                    handler.post(command);
                }
            };
        }
    
        /**
         * Creates a new response delivery interface, mockable version
         * for testing.
         * @param executor For running delivery tasks
         */
        public ExecutorDelivery(Executor executor) {
            mResponsePoster = executor;
        }
    
        @Override
        public void postResponse(Request<?> request, Response<?> response) {
            postResponse(request, response, null);
        }
    
        @Override
        public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
            request.markDelivered();
            request.addMarker("post-response");
            mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
        }
    
        @Override
        public void postError(Request<?> request, VolleyError error) {
            request.addMarker("post-error");
            Response<?> response = Response.error(error);
            mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
        }
    
        /**
         * A Runnable used for delivering network responses to a listener on the
         * main thread.
         */
        @SuppressWarnings("rawtypes")
        private class ResponseDeliveryRunnable implements Runnable {
            private final Request mRequest;
            private final Response mResponse;
            private final Runnable mRunnable;
    
            public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
                mRequest = request;
                mResponse = response;
                mRunnable = runnable;
            }
    
            @SuppressWarnings("unchecked")
            @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()) {
                    mRequest.deliverResponse(mResponse.result);
                } else {
                    mRequest.deliverError(mResponse.error);
                }
    
                // If this is an intermediate response, add a marker, otherwise we're done
                // and the request can be finished.
                if (mResponse.intermediate) {
                    mRequest.addMarker("intermediate-response");
                } else {
                    mRequest.finish("done");
                }
    
                // If we have been provided a post-delivery runnable, run it.
                if (mRunnable != null) {
                    mRunnable.run();
                }
           }
        }
    }
    
    

    其构造方法唯一目的就是实例化了Excutor类型的mResponsePoster,Volley默认调用的是第一个构造方法,也就是包装了一个Handler.该类最主要的方法是postResponse,其核心的实现

    mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
    
    

    执行的是ResponseDeliveryRunnable的run方法,而run方法中是通过

    mRequest.deliverResponse(mResponse.result);
    
    

    而Request的该方法则是由有其具体的实现类 StringRequest,JsonRequest,ImageRequest实现,其实现都一致,则是

        @Override
        protected void deliverResponse(T response) {
            mListener.onResponse(response);
        }
    

    调用回调方法。

    因此,整个分发过程就清晰了,通过Dispatcher进行处理的每个Request,对request进行处理完,则通过ResponseDelivery进行交付,其交付通过得到一个UI线程的handler,通过该Handler的post,调用Request类的delivery方法,在该方法中,又会调用我们构造request时,传入的回调方法。

  • 相关阅读:
    [读书笔记]-大话数据结构-4-栈与队列(二)-队列
    [读书笔记]-大话数据结构-4-栈与队列(一)-栈、共享栈和链栈
    [读书笔记]-大话数据结构-3-线性表(二)-线性表的链式存储
    [读书笔记]-大话数据结构-3-线性表(一)-线性表的顺序存储
    [读书笔记]-大话数据结构-2-算法
    [读书笔记]-大话数据结构-1-数据结构绪论
    Linux Shell脚本教程:30分钟玩转Shell脚本编程(笔记)
    scikit-learn学习
    xampp启动遇到的小问题
    选项卡小结
  • 原文地址:https://www.cnblogs.com/qifengshi/p/7080875.html
Copyright © 2011-2022 走看看