Volley请求的重发机制

暮鼓集    行走集

原作于2017年01月02日

在发送网络请求时,常常会遇到超时、回应错误等情形,这时便需要考虑是否重发请求。Volley提供了一套机制,用于检查问题及重发请求,这个机制的核心是RetryPolicy接口。

RetryPolicy

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.
     * @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;
}

方法getCurrentTimeout()返回请求超时的值,以毫秒为单位。Volley的Network底层执行请求操作时,会将这个值用作请求的超时时间,当超时发生时,就会触发RetryPolicy。

方法getCurrentRetryCount()返回请求的当前重发计数,往往使用这个计数与预定义的最大重试次数比较,一旦达到最大重试次数,就会停止重发。

最为重要的是方法retry(VolleyError error),在请求出现问题时,会被触发。参数error可以为如下子类,可以用于区别不同的问题原因:

TimeoutError - 超时 AuthFailureError - 鉴权失败(回应为401或403) ServerError - 服务器问题(回应为5XX) NetworkError - 网络问题(未收到回应)

(关于Volley如何触发Retry,可以参考BasicNetwork类的performRequest方法。)

在retry中,应针对错误做具体的处理,处理完成后,如果需要重发,待方法直接返回即可,如果要终止重发,需要抛出error。

给Request指定RetryPolicy

Volley为每个请求设计成可以使用不同的重试策略,这通过方法setRetryPolicy来传入RetryPolicy 的一个实例。

public Request<?> setRetryPolicy(RetryPolicy retryPolicy)

如果没有调用这个方法,则默认使用DefaultRetryPolicy。

DefaultRetryPolicy

DefaultDetryPolicy可以是RetryPolicy接口的一个最简单的实现,它被包含了Volley库中,用作缺省的重发机制。

public class DefaultRetryPolicy implements RetryPolicy {
   private int mCurrentTimeoutMs; // timeout值
    private int mCurrentRetryCount; // 重试计数器 
    private final int mMaxNumRetries; // 最大重试次数

   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;
    }
}

通过retry方法可以看到,DefaultDetryPolicy的处理策略是,每次被触发时,将 计数器mCurrentRetryCount加1,当计算器mCurrentRetryCount 未超过最大重试次数mMaxNumRetries时,返回,这时请求将被重发。

注意这时超时时间mCurrentTimeoutMs增加一个比例mBackoffMultiplier,这表示重试时,会允许更久的超时时间,减少Timeout问题发生的几率。

如超过重试次数,则抛出error,停止重发。

对鉴权失败执行重发

如果使用OAuth的HTTP API,那么常常会遇到Access Token失效的情况,这时就要求我们使用Refresh Token重新换取Token,再重发当前请求。 我的做法如下:

   @Override
    public void retry(VolleyError error) throws VolleyError {

        mCurrentRetryCount++;
        mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
        if (!hasAttemptRemaining()) {
            throw error;
        }

        if (error instanceof AuthFailureError  ) {
            Token token = dan.getToken();
            String refreshToken = token.getRefreshToken();

            if( refreshToken !=null && !refreshToken.isEmpty() ) {
                mAuth.refresh(new OnResultListener() {
                    @Override
                    public void onResult(Result result) {
                        if( result.isOK() )
                            mVolleyClient.addToRequestQueue( mRequest );
                    }
                });
            }

            throw error;
        }
    }

在这里,使用error instanceof AuthFailureError 判断是否鉴权失败,如果是,则终止当前请求的重发,通过mAuth.refresh发送获取AccessToken请求,并在其正确的回应中将当前请求在加入队列。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值