请求重试策略的相关接口和类:RetryPolicy和DefaultRetryPolicy
RetryPolicy的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 /** * 请求的重新请求策略 */ public interface RetryPolicy { /** * 获取当前请求用时(用于Log) */ public int getCurrentTimeout(); /** * 已经重新请求了几次 */ public int getCurrentRetryCount(); /** * 确定是否重试,参数为这次异常的具体信息。在请求异常时此接口会被调用,可在此函数实现中抛出传入的异常表示停止重试。 */ public void retry(VolleyError error) throws VolleyError; }
接口定义了三个方法:获取当前超时时间、获取重试次数和重试。最重要的是第三个方法
1 public void retry(VolleyError error) throws VolleyError
第三个方法会抛出异常,也就是说在retry内部会抛出异常,在retry内部的操作是变更重试策略的属性,如超时时间和重试次数,当超过了重试策略设定的限定就会抛出异常。需要注意的是:retry并不是真正的去重新发出网络请求。请求的重试是在BasicNetwork内实现的。
DefaultRetryPolicy,RetryPolicy的默认实现类,也是volley的默认的请求重试策略。 DefaultRetryPolicy的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class DefaultRetryPolicy implements RetryPolicy { private int mCurrentTimeoutMs; private int mCurrentRetryCount; private final int mMaxNumRetries; private final float mBackoffMultiplier; public static final int DEFAULT_TIMEOUT_MS = 2500; public static final int DEFAULT_MAX_RETRIES = 1; public static final float DEFAULT_BACKOFF_MULT = 1f; public DefaultRetryPolicy() { this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT); } public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) { mCurrentTimeoutMs = initialTimeoutMs; mMaxNumRetries = maxNumRetries; mBackoffMultiplier = backoffMultiplier; } @Override public int getCurrentTimeout() { return mCurrentTimeoutMs; } @Override public int getCurrentRetryCount() { return mCurrentRetryCount; } public float getBackoffMultiplier() { return mBackoffMultiplier; } @Override public void retry(VolleyError error) throws VolleyError { mCurrentRetryCount++; mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); if (!hasAttemptRemaining()) { throw error; } } protected boolean hasAttemptRemaining() { return mCurrentRetryCount <= mMaxNumRetries; } }
该类内部定义了重试策略的必备属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /**当前超时时间*/ private int mCurrentTimeoutMs; /**当前重试次数*/ private int mCurrentRetryCount; /**最大重试次数*/ private final int mMaxNumRetries; /**表示每次重试之前的 timeout 该乘以的因子,每重试一次,超时时间就变化一次*/ private final float mBackoffMultiplier; /**默认超时时间*/ public static final int DEFAULT_TIMEOUT_MS = 5000; /**默认最大重试次数*/ public static final int DEFAULT_MAX_RETRIES = 1;
DefaultRetryPolicy有两个构造方法,在创建实例时使用了默认的属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /** * Constructs a new retry policy using the default timeouts. * 构造时,使用了默认的几个参数 */ public DefaultRetryPolicy() { this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT); } /** * Constructs a new retry policy. * @param initialTimeoutMs 当前超时时间 * @param maxNumRetries 最大重试次数 * @param backoffMultiplier Backoff multiplier for the policy. */ public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) { mCurrentTimeoutMs = initialTimeoutMs; mMaxNumRetries = maxNumRetries; mBackoffMultiplier = backoffMultiplier; }
再看另外两个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override public void retry(VolleyError error) throws VolleyError { //重试次数+1 mCurrentRetryCount++; //超时时间每次都变化,增加 mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); if (!hasAttemptRemaining()) { //如果超过了最大重试次数就抛出异常 throw error; } } /** * 当前重试次数是否已经达到最大重试次数 */ protected boolean hasAttemptRemaining() { return mCurrentRetryCount <= mMaxNumRetries; }
hasAttemptRemaining()方法返回的是,当前请求次数是否已经超过了最大的重试次数。retry()方法则是定义重试请求后属性的变化,如果超过了最大次数那么抛出异常。
真正的网络请求的重试是在BasicNetwork内实现的,现在看下BasicNetwork中负责网络请求的performRequest方法的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 /** * 执行具体的网络请求 ,需要Volley的Request,返回的是可以被传递的响应 */ @Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); //这里使用while(true)的含义是:保证请求重试策略的执行。 //如果网络正常返回结果 那么直接return //如果需要进行请求重试,就用到这里了,保证了可以进行请求重试 while (true) { ...... try { ................... return new NetworkResponse(statusCode, responseContents, responseHeaders, false); //如果发生超时,认证失败等错误,进行重试操作,直到成功、抛出异常(不满足重试策略等)结束 //当catch后没有执行上边的return 而当前又是一个while(true)循环,可以保证下面的请求重试的执行,是利用循环进行请求重试,请求重试策略只是记录重试的次数、超时 时间等内容。 } catch (SocketTimeoutException e) { //当出现异常的时候,尝试进行请求重试 attemptRetryOnException("socket", request, new TimeoutError());</span> } catch (ConnectTimeoutException e) { //当出现异常的时候,尝试进行请求重试 attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException e) { //url不正常异常 throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) { //当出现IO异常时,在try内读取数据体时,如果出现IO异常,那么捕获异常,继续完成创建NetworkResponse的过程 int statusCode = 0; NetworkResponse networkResponse = null; //如果响应不为空 if (httpResponse != null) { //获取返回的状态码 statusCode = httpResponse.getStatusLine().getStatusCode(); } else { //响应为空就表明 网络连接错误 throw new NoConnectionError(e); } VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); if (responseContents != null) { //根据状态码、响应的实体数、响应头信息创建可被传递的响应 networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false); //如果状态码是授权未通过 if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) { //请求重试策略 attemptRetryOnException("auth", request, new AuthFailureError(networkResponse)); } else { // TODO: Only throw ServerError for 5xx status codes. throw new ServerError(networkResponse); } } else { throw new NetworkError(networkResponse); } } } }
performRequest(Request<?>request)方法是执行网络请求的方法,请求重试也是在这里进行。在方法的内部是用while(true)括起来的,也就是说如果该方法正常执行完毕或者抛出异常时,必然就跳出循环了,但是如果请求失败没有return并且在catch内也没有超过重试策略限定条件时,必然会while(true)下重新请求一次,这样就达到了重试的目的。
attemptRetryOnException()方法的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 /** * 请求重试策略 */ private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError { //获得该请求的请求重试策略 RetryPolicy retryPolicy = request.getRetryPolicy(); //请求重试策略的超时时间 int oldTimeout = request.getTimeoutMs(); try { //内部实现,重试次数+1 超时时间变化 //如果重试次数超过限定的最大次数,该方法抛出异常 retryPolicy.retry(exception); } catch (VolleyError e) { //当超过了最大重试次数,捕获到异常,给改请求添加标记 标记超时 request.addMarker( String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout)); //这里才是最重要的,当仍然可以进行重试的时候,不会执行到catch语句,但是当执行到catch语句的时候,表示已经不能进行重试了,就抛出异常 这样while(true)循环就断了 throw e; } //给请求添加标记,请求了多少次 request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout)); }
DefaultRetryPolicy是请求重试的策略,它规定了超时时间、超时时间的变化、请求重试次数、最大请求重试次数以及请求重试后的变化,但是DefaultRetryPolicy并没有去执行真正的网络重试请求,仅仅是规划了,真正的重试还是要到网络请求类中。
参考链接:
Android中的volley_12_请求重试策略RetryPolicy和DefaultRetryPolicy(作者的其他的文章也值得阅读)
上一篇:Volley-Network及其实现类的源码解析
下一篇:Volley-PoolingByteArrayOutputStream源码解析