How should I handle “No internet connection” with Retrofit on Android

前端 未结 8 892
一个人的身影
一个人的身影 2020-12-02 03:55

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

ConnectivityManager cm =
    (ConnectivityManager)context.getSystemSer         


        
相关标签:
8条回答
  • 2020-12-02 04:35

    you can use this code

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

    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);        
        }
    
    0 讨论(0)
  • 2020-12-02 04:41

    Since retrofit 1.8.0 this has been deprecated

    retrofitError.isNetworkError()
    

    you have to use

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

    there are multiple types of errors you can handle:

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

    CONVERSION An exception was thrown while (de)serializing a body.

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

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

    0 讨论(0)
  • 2020-12-02 04:44

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

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

    If you implement an ErrorHandler you can do something like this:

    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 ...]  
            }
        }
    
    }
    
    0 讨论(0)
  • 2020-12-02 04:45

    For Retrofit 1

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

    String getErrorMessage(Throwable e) {
        RetrofitError retrofitError;
        if (e instanceof RetrofitError) {
            retrofitError = ((RetrofitError) e);
            if (retrofitError.getKind() == RetrofitError.Kind.NETWORK) {
                return "Network is down!";
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-02 04:50

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

    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.Builder().setEndpoint(serverHost)
                         .setClient(new ConnectivityAwareUrlClient(new OkHttpClient(), ...))
    
    0 讨论(0)
  • 2020-12-02 04:52

    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
    } }
    
    0 讨论(0)
提交回复
热议问题