web-dev-qa-db-de.com

Wie gehe ich mit "Keine Internetverbindung" bei Retrofit auf Android

Ich möchte Situationen behandeln, in denen keine Internetverbindung besteht. Normalerweise würde ich laufen:

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

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

(von hier ), bevor Sie die Anforderungen an das Netzwerk senden, und benachrichtigen Sie den Benutzer, wenn keine Internetverbindung bestand.

Nach dem, was ich gesehen habe, geht Retrofit nicht speziell auf diese Situation ein. Wenn keine Internetverbindung besteht, erhalte ich nur RetrofitError mit Timeout als Grund.

Wenn ich diese Art von Check in jede HTTP-Anfrage mit Retrofit einbauen möchte, wie soll ich das tun? Oder sollte ich das überhaupt tun?.

Vielen Dank

Alex

106
AlexV

Am Ende habe ich einen benutzerdefinierten Retrofit-Client erstellt, der vor dem Ausführen einer Anforderung die Konnektivität überprüft und eine Ausnahme auslöst.

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

und verwende es dann bei der Konfiguration von RestAdapter

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

Seit Nachrüstung 1.8.0 dies ist veraltet

retrofitError.isNetworkError()

du musst benutzen

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

}

es gibt mehrere Arten von Fehlern, die Sie behandeln können:

NETWORK Während der Kommunikation mit dem Server ist eine IOException aufgetreten, z. Timeout, keine Verbindung, etc ...

CONVERSION Beim (De-) Serialisieren eines Körpers wurde eine Ausnahme ausgelöst.

HTTP Ein Nicht-200-HTTP-Statuscode wurde vom Server empfangen, z. 502, 503 usw.

UNEXPECTED Beim Versuch, eine Anforderung auszuführen, ist ein interner Fehler aufgetreten. Es wird empfohlen, diese Ausnahme erneut auszulösen, damit Ihre Anwendung abstürzt.

43

@AlexV Sind Sie sicher, dass der RetrofitError ein Timeout als Grund enthält (SocketTimeOutException, wenn getCause () aufgerufen wird), wenn keine Internetverbindung besteht?

Soweit ich weiß, wenn keine Internetverbindung besteht, enthält der RetrofitError eine ConnectionException als Ursache.

Wenn Sie einen ErrorHandler implementieren, können Sie Folgendes tun:

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 ...]  
        }
    }

}
34
saguinav

Bei Retrofit 2 verwenden wir eine OkHttp Interceptor-Implementierung, um die Netzwerkkonnektivität vor dem Senden der Anfrage zu überprüfen. Wenn kein Netzwerk vorhanden ist, lösen Sie gegebenenfalls eine Ausnahme aus.

Dies ermöglicht es einem, Netzwerkverbindungsprobleme speziell zu behandeln, bevor Retrofit gewählt wird.

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";
    }
}
31
Kevin

Wenn Sie von Ihrer http-Anfrage den Fehler Throwable erhalten, können Sie mit einer Methode wie der folgenden feststellen, ob es sich um einen Netzwerkfehler handelt:

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

UPDATE : Ich sollte sagen, dass dies nur mit Retrofit 1 funktioniert, nicht mit Retrofit 2.

5
IgorGanapolsky

tun Sie dies einfach, und Sie werden auch bei Problemen wie benachrichtigt

UnknownHostException

,

SocketTimeoutException

und andere.

 @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
} }
5
Deepak sharma

sie können diesen Code verwenden

Response.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

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

Implementierung in Ihre Methoden

        @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);        
    }
1
David Hackro