volley implementar example android retrofit

implementar - ¿Cómo debo manejar "Sin conexión a Internet" con Retrofit en Android



retrofit post (6)

Me gustaría manejar situaciones cuando no hay conexión a Internet. Por lo general, corría:

ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();

(desde here ) antes de enviar las solicitudes a la red y notificar al usuario si no hay conexión a Internet.

Por lo que vi, Retrofit no maneja esta situación específicamente. Si no hay conexión a Internet, solo obtendré RetrofitError con timeout como razón.

Si quisiera incorporar este tipo de control en cada solicitud HTTP con Retrofit, ¿cómo debería hacerlo? O debería hacerlo en absoluto.

Gracias

Alex


@AlexV ¿está seguro de que RetrofitError contiene un tiempo de espera como motivo (SocketTimeOutException cuando se llama a getCause ()) cuando no hay conexión a Internet?

Hasta donde yo sé, cuando no hay conexión a Internet, RetrofitError contiene una ConnectionException como causa.

Si implementa un ErrorHandler , puede hacer algo como esto:

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


Con Retrofit 2, utilizamos una implementación OkHttp Interceptor para verificar la conectividad de red antes de enviar la solicitud. Si no hay red, lanza una excepción según corresponda.

Esto le permite a uno manejar específicamente problemas de conectividad de red antes de presionar Retrofit.

import java.io.IOException; import okhttp3.Interceptor; import okhttp3.Response; import rx.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"; } }


Cuando obtiene un error Throwable de su solicitud http, puede detectar si se trata de un error de red con un método como este:

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

ACTUALIZACIÓN : Debo decir que esto solo funciona con Retrofit 1, no Retrofit 2.


Desde la actualización 1.8.0 esto ha quedado obsoleto

retrofitError.isNetworkError()

tienes que usar

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

hay varios tipos de errores que puede manejar:

NETWORK Se produjo una IOException al comunicarse con el servidor, por ejemplo, Timeout, Sin conexión, etc.

CONVERSION Se produjo una excepción al (de) serializar un cuerpo.

HTTP Se recibió un código de estado HTTP no 200 del servidor, por ejemplo, 502, 503, etc.

UNEXPECTED Se produjo un error interno al intentar ejecutar una solicitud. Lo mejor es volver a lanzar esta excepción para que su aplicación falle.


Lo que terminé haciendo es crear un cliente de Retrofit personalizado que verifica la conectividad antes de ejecutar una solicitud y lanza una excepción.

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

y luego RestAdapter al configurar RestAdapter

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


puedes usar este código

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

Implementación en sus métodos

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