Android okHttp 重试策略

Android okHttp Retry policy

我正在尝试创建一个简单的包装器,它将调用服务器下载信息并解析发送的二进制数据。 对于连接,我使用名为 okhttp 的库,因为 3G 上的连接不是很可靠,我决定使用以下函数实现一个非常简单的重试功能**(请注意,此方法将始终从后台线程调用)**

private InputStream callServer() throws ServerException, NoNetworkAvailableException, ConnectionErrorException {
        NetworkOperation networkOperation = getNetworkOperation();
        InputStream inputStream = null;
        //in case of network problems we will retry 3 times separated by 5 seconds before gave up
        while (connectionFailedRetryCounter < connectionFailedMaximumAllowedRetries()) {
            connectionFailedRetryCounter++;
            try {
                inputStream = networkOperation.execute();
                break;//if this line was reached it means a successfull operation, no need to retry .
            } catch (ConnectionErrorException e) {
                if (canRetryToConnect()) {
                    Utils.forceSleepThread(Constants.Communications.ConnectionFailedTrialCounter.SLEEP_BETWEEN_REQUESTS_MILLI);//retry after 5 secs (Thread.sleep)
                } else {
                    throw e;//I give up
                }
            }

        }
        return inputStream;

    }

    private boolean canRetryToConnect() {
        return (connectionFailedRetryCounter < connectionFailedMaximumAllowedRetries()) && !canceled;
    }

这样做正确吗?还是它自己的库已经完成了(不需要实现这样的东西)?

这是方法 execute() 的作用

public InputStream execute() throws ConnectionErrorException, NoNetworkAvailableException, ServerException {

    if (!Utils.isNetworkAvailable(context)) {
        throw new NoNetworkAvailableException();
    }

    Response response = doExecute();

    if (!response.isSuccessful()) {
        throw new ServerException(response.code());
    }

    return response.body().byteStream();
}

private Response doExecute() throws ConnectionErrorException {
    Response response;
    try {
        if (getRequestType() == RequestType.GET) {
            response = executeGet();
        } else {
            response = executePost();
        }
    } catch (IOException e) {
        throw new ConnectionErrorException();
    }
    return response;
}

如果抓到 NoNetworkAvailableException,您可以避免重试。如果您知道以下尝试无论如何都会失败,请不要重试。

我会让 connectionFailedMaximumAllowedRetries() 成为常量。我怀疑您是否需要随时更改变量。

实施exponential back off。你可以让它重试 10 次。每次,您将延迟乘以 2(上限为几分钟)。例如:

  1. 尝试调用 - 失败
  2. 等待 1 秒
  3. 尝试调用 - 失败
  4. 等待 2 秒
  5. 尝试调用 - 失败
  6. 等待 4 秒
  7. ...
  8. 尝试调用 - 成功

这是非常典型的行为。如果发生短暂的中断,调用将很快再次进行并成功。如果停电时间较长,您不希望每隔几秒就不断呼叫。这为您的代码提供了使其调用通过的最佳机会。显然,如果 UI 更改需要此调用,则应注意不要惹恼用户。

Failsafe's OkHttp 支持下可以很容易地处理您的场景:

RetryPolicy<Response> retryPolicy = RetryPolicy.builder()
  .handle(ConnectionErrorException.class)
  .withMaxRetries(3)
  .withDelay(Duration.ofSeconds(5))
  .build();
Call call = client.newCall(request);
FailsafeCall failsafeCall = FailsafeCall.with(retryPolicy).compose(call);

// Execute with retries
Response response = failsafeCall.execute();

这适用于同步和异步执行并支持取消。 RetryPolicy 也支持各种其他配置。