@946898963
2018-05-18T03:25:11.000000Z
字数 5773
阅读 1515
Android控件跟框架 Android源码分析
请求重试策略的相关接口和类:RetryPolicy和DefaultRetryPolicy
RetryPolicy的源码:
/*** 请求的重新请求策略*/public interface RetryPolicy {/*** 获取当前请求用时(用于Log)*/public int getCurrentTimeout();/*** 已经重新请求了几次*/public int getCurrentRetryCount();/*** 确定是否重试,参数为这次异常的具体信息。在请求异常时此接口会被调用,可在此函数实现中抛出传入的异常表示停止重试。*/public void retry(VolleyError error) throws VolleyError;}
接口定义了三个方法:获取当前超时时间、获取重试次数和重试。最重要的是第三个方法
public void retry(VolleyError error) throws VolleyError
第三个方法会抛出异常,也就是说在retry内部会抛出异常,在retry内部的操作是变更重试策略的属性,如超时时间和重试次数,当超过了重试策略设定的限定就会抛出异常。需要注意的是:retry并不是真正的去重新发出网络请求。请求的重试是在BasicNetwork内实现的。
DefaultRetryPolicy,RetryPolicy的默认实现类,也是volley的默认的请求重试策略。
DefaultRetryPolicy的源码:
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;}@Overridepublic int getCurrentTimeout() {return mCurrentTimeoutMs;}@Overridepublic int getCurrentRetryCount() {return mCurrentRetryCount;}public float getBackoffMultiplier() {return mBackoffMultiplier;}@Overridepublic void retry(VolleyError error) throws VolleyError {mCurrentRetryCount++;mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);if (!hasAttemptRemaining()) {throw error;}}protected boolean hasAttemptRemaining() {return mCurrentRetryCount <= mMaxNumRetries;}}
该类内部定义了重试策略的必备属性:
/**当前超时时间*/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有两个构造方法,在创建实例时使用了默认的属性。
/*** 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;}
再看另外两个方法:
@Overridepublic void retry(VolleyError error) throws VolleyError {//重试次数+1mCurrentRetryCount++;//超时时间每次都变化,增加mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);if (!hasAttemptRemaining()) {//如果超过了最大重试次数就抛出异常throw error;}}/*** 当前重试次数是否已经达到最大重试次数*/protected boolean hasAttemptRemaining() {return mCurrentRetryCount <= mMaxNumRetries;}
hasAttemptRemaining()方法返回的是,当前请求次数是否已经超过了最大的重试次数。retry()方法则是定义重试请求后属性的变化,如果超过了最大次数那么抛出异常。
真正的网络请求的重试是在BasicNetwork内实现的,现在看下BasicNetwork中负责网络请求的performRequest方法的源码:
/*** 执行具体的网络请求 ,需要Volley的Request,返回的是可以被传递的响应*/@Overridepublic 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(Requestrequest)方法是执行网络请求的方法,请求重试也是在这里进行。在方法的内部是用while(true)括起来的,也就是说如果该方法正常执行完毕或者抛出异常时,必然就跳出循环了,但是如果请求失败没有return并且在catch内也没有超过重试策略限定条件时,必然会while(true)下重新请求一次,这样就达到了重试的目的。
attemptRetryOnException()方法的源码:
/*** 请求重试策略*/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(作者的其他的文章也值得阅读)