3

我正在尝试创建一个简单的包装器,它将调用服务器下载信息并解析发送的二进制数据。对于连接,我使用名为 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;
}
4

2 回答 2

1

如果你抓住了,你可以避免重试NoNetworkAvailableException。如果您知道后续尝试无论如何都会失败,请不要重试。

我会做connectionFailedMaximumAllowedRetries()一个常数。我怀疑您是否需要随时更改变量。

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

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

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

于 2016-01-28T09:28:37.497 回答
0

使用Failsafe 的 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支持各种其他配置。

于 2022-02-15T16:12:29.150 回答