Volley框架解析(四)-----Network接口及其默认实现类解析

Volley框架解析(四)—–Network接口及其默认实现类解析


1. 前言(可直接无视跳过

    前面的三篇Volley框架解析文章已经从Volley对外暴露的接口Volley.java开始,向下慢慢深入到了RequestQueue.java,这个Volley中比较核心的类,然后又分析了Volley中负责主要request调度工作的两类Dispatcher,NetworkDispatcher以及CacheDispatcher。应该是将一个request从新建,到加入队列中等待处理,如何被处理以及返回结果或者error这一系列的流程理顺了。

    但是对于一些细节的问题还是不清楚,例如request究竟是如何发送出去,通过NetworkResponse networkResponse = mNetwork.performRequest(request);这么一句话就返回了结果(response),这里面发生了些什么还不得而知,还有{#link Network#performRequest()}{#link HttpStack#performREquest()}这两个函数之间有什么区别和联系等等。

2. Network.java

    最早接触到Network这个类是在Volley.java中的newRequestQueue()函数里面,Network network = new BasicNetwork(stack);创建了一个Network接口引用,并指向了一个Volley中的默认实现类的实例BasicNetwork.java,这个默认实现类也会在这篇博客的后面详细的解析。

    经过前面几篇博客的分析,Volley.java仅仅是持有而没有使用,仅将这个引用传递给了NetworkDispatcher.java中,只有在NetworkDispatcher.java类中用到了这个Network接口,在NetowkrDispatcher.java中存在着这么一行代码,

NetworkResponse networkResponse = mNetwork.performRequest(request);

    仅仅用了一句话就将request发送出去了,并且还拿回来了一个NetworkResponse.java类对象。里面发生了什么= =,先进去Network.java里面看看:

package com.android.volley;

/**
 * An interface for performing requests.
 */
public interface Network {
    /**
     * Performs the specified request.
     * 用来发送特定的请求
     *
     * @param request Request to process
     * 即将被发送的request
     *
     * @return A {@link NetworkResponse} with data and caching metadata; will never be null
     * 请求之后返回的response, 是volley自己构造出来的一个response
     * 里面包含了返回的请求码等等。
     *
     * @throws VolleyError on errors
     */
    public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}

    对,没有看错= =,就这么点东西,仅仅一个抽象方法而已,Network.java就是一个等待被实现的接口,想看真东西,还需要进去Network network = new BasicNetwork(stack);里面所提到的BasicNetwork.java看看。

3. BasicNetwork.java

    Network.java接口的默认实现类,该类里面会处理一些request发送前后的处理工作,主要是对请求返回的httpResponse处理,以及对请求失败进行retry或者抛出异常的处理。

package com.android.volley.toolbox;

/**
 * A network performing Volley requests over an {@link HttpStack}.
 * 一个用来执行Volley中request的类
 * 在HttpStack的基础之上
 * 因为主要还是调用HttpStack接口的performRequest
 * 在这个里面的performRequest主要还是做一些整理工作
 * 比如将{@link HttpStack#performRequest()}方法返回的HttpResponse
 * 解析成Volley自己实现的NetworkResponse.java
 */

public class BasicNetwork implements Network {

    //是否允许打lo的boolean常变量
    protected static final boolean DEBUG = VolleyLog.DEBUG;

    /**
     * 这是一个阀值,用来判断一个request是否请求响应过慢了= =
     * 在后面的作用就是,如果响应时间超过了这个阀值
     * 打出log说明这个request有些慢,为了更好的反应request当前状态
     */
    private static int SLOW_REQUEST_THRESHOLD_MS = 3000;

    /**
     * 默认ByteArrayPool的大小
     * 现在只需要知道ByteArrayPool.java是Volley用来从输入流中读取数据并将其转换成字节数组的工具即可
     * 在这篇博客后面会介绍,表担心~= =
     */
    private static int DEFAULT_POOL_SIZE = 4096;

    /**
     * 网络请求的真正接口
     * 为什么这么说咧,BasicNetwork里面的performRequest()函数
     * 调用了HttpStack里的performRequest(),真正的网络请求还是通过HttpStack里面的方法实现的
     * 在Volley中实现了HttpStack接口的类有两个 HurlStack.java和HttpClientStack.java
     * 针对了不同Android系统版本,用不同的方法实现了请求。
     */
    protected final HttpStack mHttpStack;

    //表急,后面会介绍到的,现在知道是一个用于数据转换的工具类就好了
    protected final ByteArrayPool mPool;

    /**
     * @param httpStack HTTP stack to be used
     * 传入的HttpStack实现类引用
     * 整个网络请求的较核心部分就在HttpStack实现类上面咯
     */
    public BasicNetwork(HttpStack httpStack) {
        // If a pool isn't passed in, then build a small default pool that will give us a lot of
        // benefit and not use too much memory.
        this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
    }

    /**
     * @param httpStack HTTP stack to be used
     * @param pool a buffer pool that improves GC performance in copy operations
     * Volley接口分离的很明显,而且在构造函数里面也提供了很多种
     * 可以定制出适合自己的ByteArrayPool衍生类
     * 当然也可以自己来实现HttpStack的衍生类
     */
    public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
        mHttpStack = httpStack;
        mPool = pool;
    }

    /**
     * 这个方法重写的是Network的方法
     * 在这个里面再调用HttpStack里面的performRequest方法
     */
    @Override
    public NetworkResponse performRequest(Request<?> request) throws VolleyError {

        /**
         * Returns milliseconds since boot, including time spent in sleep.
         * 为了方便计算每个request所用的时间
         * 在处理每个request之前都记下此刻unix时间戳
         */
        long requestStart = SystemClock.elapsedRealtime();

        /**
         * 进入死循环= =
         * 还没弄清楚为什么要死循环
         */
        while (true) {

            /**
             * 指向HttpResponse实例的引用
             * 是调用HttpStack方法performRequest()之后返回的结果
             */
            HttpResponse httpResponse = null;

            /**
             * 返回的HttpResponse还需要经过处理
             * 并不是返回回来就是能直接使用的数据
             * 需要通过上面的ByteArrayPool将Entity转换成byte[]
             * 这个就是指向解析后的byte[]的
             */
            byte[] responseContents = null;

            //用来存放response里面header的信息,包含了状态码等
            Map<String, String> responseHeaders = Collections.emptyMap();


            try {
                /**
                 * Gather headers.
                 * 设置header
                 * 从缓存中收集上次相同request的信息
                 */
                Map<String, String> headers = new HashMap<String, String>();

                /**
                 * 将缓存的信息加入到headers中
                 * headers会跟随request一起发送给服务器
                 * 在函数的定义处会讲解
                 */
                addCacheHeaders(headers, request.getCacheEntry());

                /**
                 * 通过调用HttpStack接口的performRequest()方法
                 * 获取服务器返回的HttpResponse
                 */
                httpResponse = mHttpStack.performRequest(request, headers);

                /**
                 * The first line of a Response message is the Status-Line, 
                 * consisting of the protocol version followed by a numeric status code and its associated textual phrase
                 * with each element separated by SP characters. 
                 * No CR or LF is allowed except in the final CRLF sequence.
                 * 请求返回的response第一行就是包含了状态码的一行
                 */
                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();

                /**
                 * 将头部解析成键值对的形式再返回
                 */
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());

                /**
                 * Handle cache validation.
                 * 处理缓存信息
                 * 如果返回的状态码是304(HttpStatus.SC_NOT_MODIFIED)
                 * 则进行如下的处理
                 */
                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {

                    /**
                     * 如果缓存为空的话
                     * 那就说明该请求的返回的response的body就是null
                     * 直接构造一个NetworkResponse返回
                     */
                    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
                    /**
                     * 一个返回码为304的HttpResponse的header缺少一些信息
                     * 需要我们将cache中的一些header信息加入到其中
                     * 这样组成一个完整的NetworkResponse返回
                     */
                    entry.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
                            entry.responseHeaders, true,
                            SystemClock.elapsedRealtime() - requestStart);
                }

                /**
                 * Handle moved resources
                 * 处理了重定向的问题
                 * 并将request的mRedirectUrl设定成了新的url
                 */
                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                    String newUrl = responseHeaders.get("Location");
                    request.setRedirectUrl(newUrl);
                }

                /**
                 * Some responses such as 204s do not have content.  We must check.
                 * 204(无内容)服务器成功处理了请求,但没有返回任何内容。
                 * 
                 */
                if (httpResponse.getEntity() != null) {
                    /**
                     * 如果entity不为Null
                     * 将其转换成byte数组
                     * 利用之前提到过的ByteArrayPool.java类
                     */
                  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.
                 * 获取request已经占用的时间(requestLifetime)
                 * 判断是否需要打出request的超时状态
                 */
                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                logSlowRequests(requestLifetime, request, responseContents, statusLine);

                /**
                 * 如果状态码位于200之下或者是299之上(200-299 用于表示请求成功)
                 * 则抛出IOException异常= =为什么非要抛出这个异常
                 * 在前面过滤掉了(304等情况)
                 */
                if (statusCode < 200 || statusCode > 299) {
                    throw new IOException();
                }

                /**
                 * 经过上面的层层过滤
                 * 最后留下了200~299之间的请求成功response
                 * 通过HttpResponse里面的信息构造出一个volley自己封装的NetworkResponse对象
                 */
                return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
                        SystemClock.elapsedRealtime() - requestStart);

                /**
                 * 抛出了异常之后,会用attemptREtryOnException()方法来尝试retry
                 * 主要做的工作就是看是否还有retry的机会,如果有则不停通过这个死循环
                 * 进行请求,直到请求成功或者请求的机会用完为止
                 */
            } 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) {
                /**
                 * 状态码在0~200以及299之上的response
                 * 处理的套路
                 */
                int statusCode = 0;
                NetworkResponse networkResponse = null;
                if (httpResponse != null) {
                    statusCode = httpResponse.getStatusLine().getStatusCode();
                } else {
                    //如果状态码为0,则抛出NoConnectionError
                    throw new NoConnectionError(e);
                }
                /**
                 * 如果有重定向的情况发生
                 * 用log打出
                 */
                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || 
                        statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                    VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl());
                } else {
                    VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
                }

                /**
                 * 如果返回的content内容不为Null
                 * 则构造出一个NetworkResponse
                 * 否则抛出NetworkError
                 */
                if (responseContents != null) {

                    networkResponse = new NetworkResponse(statusCode, responseContents,
                            responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);

                    /**
                     * 抛出了异常之后,会用attemptREtryOnException()方法来尝试retry
                     * 主要做的工作就是看是否还有retry的机会,如果有则不停通过这个死循环
                     * 进行请求,直到请求成功或者请求的机会用完为止
                     */
                    if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
                            statusCode == HttpStatus.SC_FORBIDDEN) {
                        attemptRetryOnException("auth",
                                request, new AuthFailureError(networkResponse));
                    } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || 
                                statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                        attemptRetryOnException("redirect",
                                request, new AuthFailureError(networkResponse));
                    } else {
                        // TODO: Only throw ServerError for 5xx status codes.
                        throw new ServerError(networkResponse);
                    }
                } else {
                    throw new NetworkError(networkResponse);
                }
            }
        }
    }

    /**
     * Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete.
     * 如果request用时超出了预先设定的阀值
     * 则打出log用于debug时候的提示
     */
    private void logSlowRequests(long requestLifetime, Request<?> request,
            byte[] responseContents, StatusLine statusLine) {
        if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
            VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " +
                    "[rc=%d], [retryCount=%s]", request, requestLifetime,
                    responseContents != null ? responseContents.length : "null",
                    statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount());
        }
    }

    /**
     * Attempts to prepare the request for a retry. If there are no more attempts remaining in the
     * request's retry policy, a timeout exception is thrown.
     * 每次尝试都会使retry机会减少1,如果机会没有了,则抛出请求超时的exception
     *
     * @param request The request to use.
     */
    private static void attemptRetryOnException(String logPrefix, Request<?> request,
            VolleyError exception) throws VolleyError {
        RetryPolicy retryPolicy = request.getRetryPolicy();
        int oldTimeout = request.getTimeoutMs();

        try {
            retryPolicy.retry(exception);
        } catch (VolleyError e) {
            request.addMarker(
                    String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
            throw e;
        }
        request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
    }



    /**
     * 添加上缓存的header
     * 如果有之前的缓存的信息
     * 将里面的信息取出放入header中
     * 
     * 这里面涉及到了一个条件请求
     * 如果有缓存的话,header上面会带上一个If-Modified-Since关键字
     * 服务器会先比较信息modified的时间,如果服务端的数据没有发生变化就返回304(也就是上面的 HttpStatus.SC_NOT_MODIFIED)
     * 如果服务器的数据发生了变化,则会返回状态码200以及请求需要的数据(意思就是本地的数据需要刷新了,缓存不管用了)
     */
    private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {
        // If there's no cache entry, we're done.
        if (entry == null) {
            return;
        }

        if (entry.etag != null) {
            headers.put("If-None-Match", entry.etag);
        }

        if (entry.lastModified > 0) {
            Date refTime = new Date(entry.lastModified);
            headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
        }
    }


    protected void logError(String what, String url, long start) {
        long now = SystemClock.elapsedRealtime();
        VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url);
    }

    /** 
     * Reads the contents of HttpEntity into a byte[].
     * 从HttpEntity中读取数据,并通过ByteArrayPool将其转换成byte[]
     * 暂时不用管太多= =,等后面介绍到ByteArrayPool.java的时候就会明白
     */
    private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {

        PoolingByteArrayOutputStream bytes =
                new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());

        byte[] buffer = null;

        try {
            InputStream in = entity.getContent();
            if (in == null) {
                throw new ServerError();
            }

            /**
             * 获取一个大小为1024的缓冲区
             */
            buffer = mPool.getBuf(1024);

            int count;
            //将content的内容通过流每次最大读出1024个byte, 全部读出并写入bytes
            while ((count = in.read(buffer)) != -1) {
                bytes.write(buffer, 0, count);
            }
            return bytes.toByteArray();
        } finally {
            try {
                // Close the InputStream and release the resources by "consuming the content".
                entity.consumeContent();
            } catch (IOException e) {
                // This can happen if there was an exception above that left the entity in
                // an invalid state.
                VolleyLog.v("Error occured when calling consumingContent");
            }
            /**
             * 在所有工作完成之后
             * 需要将从mPool中拿出的buffer缓冲区回收
             */
            mPool.returnBuf(buffer);
            bytes.close();
        }
    }

    /**
     * Converts Headers[] to Map<String, String>.
     * 将返回的response里面的header[]
     * 全部转换成Map里面的键值对形式
     */
    protected static Map<String, String> convertHeaders(Header[] headers) {
        Map<String, String> result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
        for (int i = 0; i < headers.length; i++) {
            result.put(headers[i].getName(), headers[i].getValue());
        }
        return result;
    }
}

4. ByteArrayPool.java

    ByteArrayPool.java是用来将HttpResponse中Entity通过stream的形式转换成byte[],主要的作用是提供缓冲区,用来辅助流数据的读取,在使用完成之后需要将使用过的缓冲区还给ByteArrayPool,ByteArrayPool里会对这些byte[]进行简单的回收处理。

/**
 * 用来给外界提供byte[]作为缓冲区的一个工具类
 */
public class ByteArrayPool {
    /**
     * The buffer pool, arranged both by last use and by buffer size 
     */
    private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>();
    private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64);

    /**
     * The total size of the buffers in the pool
     * 缓冲池的当前大小
     */
    private int mCurrentSize = 0;

    /**
     * The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay
     * under this limit.
     * 缓冲池当前的大小的阀值
     * 超过了该值则会对缓冲池进行回收处理
     */
    private final int mSizeLimit;

    /**
     * Compares buffers by size
     * 比较两个缓冲区的大小的规则
     * 如果返回一个负数,则表示前一个数要小
     * 如果返回0,则表示两个数字相等
     * 如果返回一个正数,则表示后一个数要小
     * 
     */
    protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() {
        @Override
        public int compare(byte[] lhs, byte[] rhs) {
            return lhs.length - rhs.length;
        }
    };

    /**
     * @param sizeLimit the maximum size of the pool, in bytes
     * 用来修改缓冲池的大小阀值
     */
    public ByteArrayPool(int sizeLimit) {
        mSizeLimit = sizeLimit;
    }

    /**
     * Returns a buffer from the pool if one is available in the requested size, or allocates a new
     * one if a pooled one is not available.
     * 从mBuffersBySize中调出一个缓冲区来
     * 如果大小符合要求,则直接返回给调用者
     * 如果没有符合要求的,直接创建一个新的byte[]返回
     *
     * @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be
     *        larger.
     * @return a byte[] buffer is always returned.
     */
    public synchronized byte[] getBuf(int len) {
        for (int i = 0; i < mBuffersBySize.size(); i++) {
            byte[] buf = mBuffersBySize.get(i);
            if (buf.length >= len) {
                mCurrentSize -= buf.length;
                mBuffersBySize.remove(i);
                mBuffersByLastUse.remove(buf);
                return buf;
            }
        }
        return new byte[len];
    }

    /**
     * Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted
     * size.
     * 
     * @param buf the buffer to return to the pool.
     */
    public synchronized void returnBuf(byte[] buf) {

        //如果buf为空或者超出了规定的大小,不管就行了,这种缓冲区用不着回收,因为= =根本就不符合要求嘛

        if (buf == null || buf.length > mSizeLimit) {
            return;
        }

        //如果buf符合要求,则将其加入到最近使用的队列中去

        mBuffersByLastUse.add(buf);

        /**
         * 通过二分查找,比较规则为BUF_COMPARATOR,找出新进来的buf应该处于的位置
         * 随后将buf插入到mBufferBySize的队列里面
         */
        int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);
        if (pos < 0) {
            pos = -pos - 1;
        }

        mBuffersBySize.add(pos, buf);

        //当前总缓冲区大小变大
        mCurrentSize += buf.length;

        //对整个缓冲池的大小做出调整
        trim();
    }

    /**
     * Removes buffers from the pool until it is under its size limit.
     * 调整缓冲区的大小
     * 直到mCurrentSize在限制大小之下
     */
    private synchronized void trim() {

        while (mCurrentSize > mSizeLimit) {
            byte[] buf = mBuffersByLastUse.remove(0);
            mBuffersBySize.remove(buf);
            mCurrentSize -= buf.length;
        }
    }

}

5. RetryPolicy.java

    在BasicNetwork.java这个类中,通过死循环加上try,catch的方式,不停的对一个request进行重复的处理,里面涉及到了RetryPolicy.java接口以及其默认实现类,这个接口是用来专门处理一个request在发送以及得到服务器响应返回结果的过程中出现的问题。通过有限次数的不断扩大request响应时间阀值,再次发送request的方式来达到一个retry的目的。和Network.java类似的,RetryPolicy.java也仅仅就是提供了抽象方法,想把具体的实现内容弄明白还需要去默认实现类DefaultRetryPolicy.java中去。

package com.android.volley;

/**
 * Retry policy for a request.
 * 该类用来管理request的调整及重新发送
 * 所谓调整就是将request响应时间(timeout)放宽
 */
public interface RetryPolicy {

    /**
     * Returns the current timeout (used for logging).
     */
    public int getCurrentTimeout();

    /**
     * Returns the current retry count (used for logging).
     */
    public int getCurrentRetryCount();

    /**
     * Prepares for the next retry by applying a backoff to the timeout.
     * 为下一次request做好准备,通过不停地来放宽timeout时间限制
     * 在DefaultRetryPolicy.java中好理解一些
     * 
     * @param error The error code of the last attempt.
     * @throws VolleyError In the event that the retry could not be performed (for example if we
     * ran out of attempts), the passed in error is thrown.
     */
    public void retry(VolleyError error) throws VolleyError;
}

5. DefaultRetryPolicy.java

    DefaultRetryPolicy.java描述了对待Volley中涉及Network的request的策略方针,可以理解为重试策略方针,也就是对那些在网络请求失败的request处理方法。里面包含了retry的最大次数(mMaxNumRetries),当前请求次数(mCurrentRetryCount)以及请求超时的时间阀值(mCurrentTimeoutMs)等。每个Request里面都包含了一个RetryPolicy.java实现类,在处理的时候可以通过getRetryPolicy()方法获得。

package com.android.volley;

/**
 * Default retry policy for requests.
 */
public class DefaultRetryPolicy implements RetryPolicy {
    /** 
     * The current timeout in milliseconds. 
     * 请求超时的时间数
     */
    private int mCurrentTimeoutMs;

    /** 
     * The current retry count.
     * 当前请求的重试次数
     */
    private int mCurrentRetryCount;

    /** 
     * The maximum number of attempts. 
     * 重复尝试的最大次数
     **/
    private final int mMaxNumRetries;

    /** 
     * The backoff multiplier for the policy.
     * 暂时不明白这个有什么用
     * 根据后面的来看好像是一个用于放宽timeout时间限制的系数
     * 这个系数越大每次retry的时候放宽的程度也就越大
     */
    private final float mBackoffMultiplier;

    /** The default socket timeout in milliseconds */
    public static final int DEFAULT_TIMEOUT_MS = 2500;

    /** The default number of retries */
    public static final int DEFAULT_MAX_RETRIES = 0;

    /** The default backoff multiplier */
    public static final float DEFAULT_BACKOFF_MULT = 1f;


    /**
     * Constructs a new retry policy using the default timeouts.
     * 默认的构造器,2.5s的超时,
     * 最大重试数为0,也就是request请求超时了就不要再自动重试了
     */
    public DefaultRetryPolicy() {
        this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT);
    }

    /**
     * Constructs a new retry policy.
     * @param initialTimeoutMs The initial timeout for the policy.
     * @param maxNumRetries The maximum number of retries.
     * @param backoffMultiplier Backoff multiplier for the policy.
     */
    public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {
        mCurrentTimeoutMs = initialTimeoutMs;
        mMaxNumRetries = maxNumRetries;
        mBackoffMultiplier = backoffMultiplier;
    }

    /**
     * Returns the current timeout.
     */
    @Override
    public int getCurrentTimeout() {
        return mCurrentTimeoutMs;
    }

    /**
     * Returns the current retry count.
     */
    @Override
    public int getCurrentRetryCount() {
        return mCurrentRetryCount;
    }

    /**
     * Returns the backoff multiplier for the policy.
     */
    public float getBackoffMultiplier() {
        return mBackoffMultiplier;
    }

    /**
     * Prepares for the next retry by applying a backoff to the timeout.
     * 该方法定义在RetryPolicy.java中。
     * 为下一次重试request做准备,好像是通过延长服务器响应时间的限制 = =
     * 每次对timeout的时间限制都放宽了mBackoffMultiplier个单位。让服务器多一点时间去响应
     * 
     * @param error The error code of the last attempt.
     * 最后一次request服务器给出的错误码
     */
    @Override
    public void retry(VolleyError error) throws VolleyError {
        mCurrentRetryCount++;
        mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
        if (!hasAttemptRemaining()) {
            throw error;
        }
    }

    /**
     * Returns true if this policy has attempts remaining, false otherwise.
     * 这个是用来判断是否还有retry机会的
     */
    protected boolean hasAttemptRemaining() {
        return mCurrentRetryCount <= mMaxNumRetries;
    }
}

    到这里对Network.java接口以及RetryPolicy.java接口的代码就分析完了,现在是清楚了在NetworkDispatcher.java调用了mNetwork.performRequest()之后发生了什么事情,还弄清楚了request在网络请求发送之后,出现了各种问题会怎么处理(重试策略),但还不知道最核心的网络请求是如何发生的,也就是在BasicNetwork.java中的下面这行代码。

httpResponse = mHttpStack.performRequest(request, headers);

    这行代码就涉及到了后面的HttpStack.java接口及其两个实现类了,在下篇博客会对源代码进行逐句的分析。今天的分析就到这里咯~~~~,有什么不对的地方还望各juju指出,小达一定改正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值