简体   繁体   English

在Retrofit Android中手动重试请求的好方法

[英]Good approach to manually retry requests in Retrofit Android

I understand retrofit automatically retries on failures, but I want to check for a specific error. 我了解翻新会自动重试失败,但我想检查特定的错误。 If the error is due to a certain HTTP code, I need to retry that request after modifying it. 如果错误是由于某个HTTP代码引起的,那么我需要在修改后重试该请求。

This can be easily done using synchronous calls, but I am making an asynchronous call (by passing callbacks). 使用同步调用可以轻松完成此操作,但是我正在进行异步调用(通过传递回调)。 When I get the error in the callback, I want to retry the request - but all I have is the RetrofitError object (and I have lost the request body). 当我在回调中收到错误时,我想重试请求-但我仅有的就是RetrofitError对象(并且我丢失了请求正文)。

I have multiple requests going on from the same activity (concurrently) and so I am avoiding saving all requests and nullifying them on success. 我有多个来自同一活动的请求(同时发生),所以我避免保存所有请求并在成功后将其无效。

Is there a better way to achieve this requirement ? 是否有更好的方法来满足此要求?

Here's what you could try. 这是您可以尝试的方法。 First the network request method: 首先是网络请求方法:

void getDataFromServer(final int dataId) {
     ...

    dataService.getDataFromServer(dataId, new Callback<ResultData>() {
        @Override
        public void success(final ResultData data, final Response response) {
            retries.set(0);
            ...
        }

        @Override
        public void failure(RetrofitError error) {
            if (RetrofitErrorHandler.retry(activity, progressDialog, error, retries, activity.getString(R.string.error_getting_data))) {
                getDataFromServer(dataId);// retry this method
            } else {
               // let user know we counldn't get data
               ...
            }
        }
    });

}

Here you could check if the request should be retried and return true if we should retry and false if we shouldn't. 在这里,您可以检查是否应重试该请求,如果应该重试,则返回true,否则,则返回false。

The first half of retry checks if the status code of the error (see r.getStatus() ) equals which ever status code is of interest to you (see STATUS_CODE_RETRY ) which could be any server status code (eg 401, 404. etc.). 重试的前半部分检查错误的状态码(请参见r.getStatus() )是否等于您感兴趣的状态码(请参见STATUS_CODE_RETRY ),该状态码可以是任何服务器状态码(例如401、404等)。 )。

The second half of retry first checks to see if it was a network error (see error.isNetworkError() ) and if it is then it increments the retry counter and returns true which means that the network request will be retried. 重试的后半部分首先检查是否是网络错误(请参阅error.isNetworkError() ),如果是,则它增加重试计数器并返回true,这意味着将重试网络请求。 If the error is a network error (see error.isNetworkError() ) and the retry counter is greater than your desired max number of retries (see NUM_RETRIES ) then it returns false so that the request doesn't get triggered again. 如果错误网络错误(请参阅error.isNetworkError() ),并且重试计数器大于所需的最大重试次数(请参见NUM_RETRIES ),那么它将返回false,以便不会再次触发请求。 The next portion is the no connection check, where a network error has occurred but it's not a timeout so it must be an issue with the connection. 下一部分是无连接检查,其中发生了网络错误,但不是超时,因此它一定是连接问题。 This check returns false, as the network request should not be retried and the user should be notified of the connection issues. 该检查返回false,因为不应重试网络请求,并且应将连接问题通知用户。 The final check is the non network error check, which indicates that an error has occurred that isn't a result of a network error. 最后的检查是非网络错误检查,它表示发生的错误不是网络错误的结果。 Once again, false is returned so the request isn't retried and the user is notified. 再次返回false,因此不会重试该请求并通知用户。

public static boolean retry(Activity act, RetrofitError error, AtomicInteger retries, String uploadErrorMsg){
    // this is the first half of the retry check
    Response r = error.getResponse();
    if (r != null && r.getStatus() == STATUS_CODE_RETRY){
        Log.v(TAG, "STATUS_CODE_RETRY!");
        ...
        return true;
    }
    // this is the second half of the retry check
    if (error.isNetworkError()) {
        if (error.getCause() instanceof SocketTimeoutException) {//connection timeout check
            if(retries.incrementAndGet() < NUM_RETRIES){ // retry if you can
                return true;
            } else { // if you can't retry anymore
                retries.set(0);
                Log.i(TAG, act.getClass().getSimpleName() + " has no more retries " + act.getString(R.string.timeout_msg));
                return false;
            }
        } else {//no connection check
            retries.set(0);
            Log.i(TAG, act.getClass().getSimpleName() + " " + act.getString(R.string.timeout_msg)+ " " + uploadErrorMsg);
            return false;
        }
    } else { //non network error check
        retries.set(0); 
        Log.i(TAG, act.getClass().getSimpleName() + " " + act.getString(R.string.err_msg)+ " " + uploadErrorMsg);
        return false;
    }
}  

Hope this helped. 希望这会有所帮助。

If you are using OkHttp as your HttpClient and have updated to Retrofit >= 1.9.0 then you can use the new Interceptor . 如果您使用OkHttp作为HttpClient并已更新为Retrofit > = 1.9.0则可以使用新的Interceptor Specifically, an Application Interceptor will let you retry and make multiple calls . 具体来说, 应用程序拦截器将让您retry and make multiple calls

You can see example pseudocode I posted on a similar question for handling expired tokens. 您可以看到我在类似问题上发布的示例伪代码,用于处理过期的令牌。

Also note, Retrofit 2.0 will have Interceptors according to this GitHub ticket . 另请注意,根据此GitHub票证Retrofit 2.0将具有Interceptors That will remove the dependence on OkHttp , though I still recommend using it. 这将消除对OkHttp的依赖,尽管我仍然建议使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM