我应该如何在 Android 上使用 Retrofit 处理“无互联网连接”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20786593/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:28:17  来源:igfitidea点击:

How should I handle "No internet connection" with Retrofit on Android

androidretrofit

提问by AlexV

I'd like to handle situations when there is no internet connection. Usually I'd run:

我想处理没有互联网连接的情况。通常我会跑:

ConnectivityManager cm =
    (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
                  activeNetwork.isConnectedOrConnecting();

(from here) before sending the requests to the network and notify user if there were no internet connection.

(从这里)在将请求发送到网络之前通知用户,如果没有互联网连接。

From what I saw Retrofit does not handle this situation specifically. If there is no internet connection I'll just get RetrofitErrorwith timeout as a reason.

据我所见,Retrofit 并没有专门处理这种情况。如果没有互联网连接,我只会RetrofitError以超时为理由。

If I'd like to incorporate this kind of check into every HTTP request with Retrofit, how should I do it? Or should I do it at all.

如果我想通过 Retrofit 将这种检查合并到每个 HTTP 请求中,我应该怎么做?或者我应该这样做。

Thanks

谢谢

Alex

亚历克斯

采纳答案by AlexV

What I ended up doing is creating a custom Retrofit client that checks for connectivity before executing a request and throws an exception.

我最终做的是创建一个自定义 Retrofit 客户端,它在执行请求之前检查连接并抛出异常。

public class ConnectivityAwareUrlClient implements Client {

    Logger log = LoggerFactory.getLogger(ConnectivityAwareUrlClient.class);

    public ConnectivityAwareUrlClient(Client wrappedClient, NetworkConnectivityManager ncm) {
        this.wrappedClient = wrappedClient;
        this.ncm = ncm;
    }

    Client wrappedClient;
    private NetworkConnectivityManager ncm;

    @Override
    public Response execute(Request request) throws IOException {
        if (!ncm.isConnected()) {
            log.debug("No connectivity %s ", request);
            throw new NoConnectivityException("No connectivity");
        }
        return wrappedClient.execute(request);
    }
}

and then use it when configuring RestAdapter

然后在配置的时候使用 RestAdapter

RestAdapter.Builder().setEndpoint(serverHost)
                     .setClient(new ConnectivityAwareUrlClient(new OkHttpClient(), ...))

回答by Muhammad Alfaifi

Since retrofit 1.8.0this has been deprecated

自改造以来,1.8.0这已被弃用

retrofitError.isNetworkError()

you have to use

你必须使用

if (retrofitError.getKind() == RetrofitError.Kind.NETWORK)
{

}

there are multiple types of errors you can handle:

您可以处理多种类型的错误:

NETWORKAn IOException occurred while communicating to the server, e.g. Timeout, No connection, etc...

NETWORK与服务器通信时发生 IOException,例如超时、无连接等...

CONVERSIONAn exception was thrown while (de)serializing a body.

CONVERSION(反)序列化主体时抛出异常。

HTTPA non-200 HTTP status code was received from the server e.g. 502, 503, etc...

HTTP从服务器收到非 200 HTTP 状态代码,例如 502、503 等...

UNEXPECTEDAn internal error occurred while attempting to execute a request. It is best practice to re-throw this exception so your application crashes.

UNEXPECTED尝试执行请求时发生内部错误。最佳做法是重新抛出此异常,以免您的应用程序崩溃。

回答by Kevin

With Retrofit 2, we use an OkHttp Interceptor implementation to check for network connectivity ahead of sending the request. If no network, throw an exception as appropriate.

对于 Retrofit 2,我们使用 OkHttp 拦截器实现在发送请求之前检查网络连接。如果没有网络,则酌情抛出异常。

This allows one to specifically handle network connectivity issues before hitting Retrofit.

这允许人们在进行改造之前专门处理网络连接问题。

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.Response;
import io.reactivex.Observable

public class ConnectivityInterceptor implements Interceptor {

    private boolean isNetworkActive;

    public ConnectivityInterceptor(Observable<Boolean> isNetworkActive) {
       isNetworkActive.subscribe(
               _isNetworkActive -> this.isNetworkActive = _isNetworkActive,
               _error -> Log.e("NetworkActive error " + _error.getMessage()));
    }

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        if (!isNetworkActive) {
            throw new NoConnectivityException();
        }
        else {
            Response response = chain.proceed(chain.request());
            return response;
        }
    }
}

public class NoConnectivityException extends IOException {

    @Override
    public String getMessage() {
        return "No network available, please check your WiFi or Data connection";
    }
}

回答by saguinav

@AlexV are you sure that the RetrofitError contains a timeout as a reason (SocketTimeOutException when getCause() is called) when there is no internet connection?

@AlexV 您确定 RetrofitError 在没有互联网连接时包含超时作为原因(调用 getCause() 时为 SocketTimeOutException)吗?

As far as I know when there is no internet connection the RetrofitError contains a ConnectionException as cause.

据我所知,当没有互联网连接时,RetrofitError 包含一个 ConnectionException 作为原因。

If you implement an ErrorHandleryou can do something like this:

如果你实现了一个ErrorHandler你可以做这样的事情:

public class RetrofitErrorHandler implements ErrorHandler {

    @Override
    public Throwable handleError(RetrofitError cause) {
        if (cause.isNetworkError()) {
            if (cause.getCause() instanceof SocketTimeoutException) {
                return new MyConnectionTimeoutException();
            } else {
                return new MyNoConnectionException();
            }
        } else {
            [... do whatever you want if it's not a network error ...]  
        }
    }

}

回答by IgorGanapolsky

For Retrofit 1

改装 1

When you get a Throwableerror from your http request, you can detect whether it is a network error with a method like this:

当您Throwable从 http 请求中收到错误时,您可以使用如下方法检测它是否是网络错误:

String getErrorMessage(Throwable e) {
    RetrofitError retrofitError;
    if (e instanceof RetrofitError) {
        retrofitError = ((RetrofitError) e);
        if (retrofitError.getKind() == RetrofitError.Kind.NETWORK) {
            return "Network is down!";
        }
    }
}

回答by Deepak sharma

just do this you will notified even for issues like

只要这样做,即使出现类似的问题,您也会收到通知

UnknownHostException

未知主机异常

,

,

SocketTimeoutException

套接字超时异常

and others.

和别的。

 @Override public void onFailure(Call<List<BrokenGitHubRepo>> call, Throwable t) {  
if (t instanceof IOException) {
    Toast.makeText(ErrorHandlingActivity.this, "this is an actual network failure :( inform the user and possibly retry", Toast.LENGTH_SHORT).show();
    // logging probably not necessary
}
else {
    Toast.makeText(ErrorHandlingActivity.this, "conversion issue! big problems :(", Toast.LENGTH_SHORT).show();
    // todo log to some central bug tracking service
} }

回答by David Hackro

you can use this code

你可以使用这个代码

Response.java

响应.java

import com.google.gson.annotations.SerializedName;

/**
 * Created by hackro on 19/01/17.
 */

public class Response {
    @SerializedName("status")
    public String status;

    public void setStatus(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }

    @SuppressWarnings({"unused", "used by Retrofit"})
    public Response() {
    }

    public Response(String status) {
        this.status = status;
    }
}

NetworkError.java

网络错误.java

import android.text.TextUtils;

import com.google.gson.Gson;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import retrofit2.adapter.rxjava.HttpException;

import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;

/**
 * Created by hackro on 19/01/17.
 */

public class NetworkError extends Throwable {
    public static final String DEFAULT_ERROR_MESSAGE = "Please try again.";
    public static final String NETWORK_ERROR_MESSAGE = "No Internet Connection!";
    private static final String ERROR_MESSAGE_HEADER = "Error Message";
    private final Throwable error;

    public NetworkError(Throwable e) {
        super(e);
        this.error = e;
    }

    public String getMessage() {
        return error.getMessage();
    }

    public boolean isAuthFailure() {
        return error instanceof HttpException &&
                ((HttpException) error).code() == HTTP_UNAUTHORIZED;
    }

    public boolean isResponseNull() {
        return error instanceof HttpException && ((HttpException) error).response() == null;
    }

    public String getAppErrorMessage() {
        if (this.error instanceof IOException) return NETWORK_ERROR_MESSAGE;
        if (!(this.error instanceof HttpException)) return DEFAULT_ERROR_MESSAGE;
        retrofit2.Response<?> response = ((HttpException) this.error).response();
        if (response != null) {
            String status = getJsonStringFromResponse(response);
            if (!TextUtils.isEmpty(status)) return status;

            Map<String, List<String>> headers = response.headers().toMultimap();
            if (headers.containsKey(ERROR_MESSAGE_HEADER))
                return headers.get(ERROR_MESSAGE_HEADER).get(0);
        }

        return DEFAULT_ERROR_MESSAGE;
    }

    protected String getJsonStringFromResponse(final retrofit2.Response<?> response) {
        try {
            String jsonString = response.errorBody().string();
            Response errorResponse = new Gson().fromJson(jsonString, Response.class);
            return errorResponse.status;
        } catch (Exception e) {
            return null;
        }
    }

    public Throwable getError() {
        return error;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        NetworkError that = (NetworkError) o;

        return error != null ? error.equals(that.error) : that.error == null;

    }

    @Override
    public int hashCode() {
        return error != null ? error.hashCode() : 0;
    }
}

Implementation in your methods

在你的方法中实现

        @Override
        public void onCompleted() {
            super.onCompleted();
        }

        @Override
        public void onError(Throwable e) {
            super.onError(e);
            networkError.setError(e);
            Log.e("Error:",networkError.getAppErrorMessage());
        }

        @Override
        public void onNext(Object obj) {   super.onNext(obj);        
    }