@946898963
2018-05-18T11:25:11.000000Z
字数 5773
阅读 1229
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;
}
@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;
}
}
该类内部定义了重试策略的必备属性:
/**当前超时时间*/
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;
}
再看另外两个方法:
@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方法的源码:
/**
* 执行具体的网络请求 ,需要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(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(作者的其他的文章也值得阅读)