मुझे एंड्रॉइड पर रेट्रोफ़िट के साथ "नो इंटरनेट कनेक्शन" कैसे संभालना चाहिए


119

जब इंटरनेट कनेक्शन नहीं है, तो मैं स्थितियों को संभालना चाहता हूं। आमतौर पर मैं दौड़ता हूँ:

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

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

( यहां से ) नेटवर्क भेजने का अनुरोध करने से पहले और इंटरनेट कनेक्शन न होने पर उपयोगकर्ता को सूचित करें।

मैंने जो देखा, उससे रेट्रोफिट विशेष रूप से इस स्थिति को नहीं संभालता है। अगर कोई इंटरनेट कनेक्शन नहीं है, तो मैं RetrofitErrorएक कारण के रूप में टाइमआउट के साथ मिलूंगा।

अगर मैं रिट्रोफिट के साथ हर HTTP अनुरोध में इस तरह के चेक को शामिल करना चाहता हूं, तो मुझे यह कैसे करना चाहिए? या मुझे यह बिल्कुल करना चाहिए।

धन्यवाद

एलेक्स


Http कनेक्शन के लिए टाइमआउट अपवाद को पकड़ने के लिए आप try-catch ब्लॉक का उपयोग कर सकते हैं। फिर, उपयोगकर्ताओं को इंटरनेट कनेक्शन स्थिति के बारे में बताएं। सुंदर नहीं है लेकिन एक वैकल्पिक समाधान है।
तुगरुल

8
हाँ, लेकिन एंड्रॉइड के साथ जांच करना बहुत तेज़ है अगर इसमें सॉकेट से कनेक्शन टाइमआउट पाने के लिए प्रतीक्षा करने के बजाय इंटरनेट कनेक्शन है
एलेक्सा डिक

एंड्रॉइड क्वेरी "कोई इंटरनेट नहीं" संभालती है और जल्द ही संबंधित त्रुटि कोड देता है। शायद यह aQuery के साथ इसे बदलने के लायक है? एक अन्य समाधान नेटवर्क परिवर्तन पर एक श्रोता बनाना है और इस प्रकार एप्लिकेशन को अनुरोध भेजने से पहले इंटरनेट उपलब्धता के बारे में पता चल जाएगा।
स्टेन

रेट्रोफिट 2 के लिए, github.com/square/retrofit/issues/1260
ghanbari

जवाबों:


63

मैंने जो कुछ किया वह एक कस्टम रेट्रोफिट क्लाइंट बना रहा है जो अनुरोध को निष्पादित करने से पहले कनेक्टिविटी की जांच करता है और एक अपवाद फेंकता है।

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

और फिर इसे कॉन्फ़िगर करते समय उपयोग करें RestAdapter

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

1
आपका NetworkConnectivityManager वर्ग कहाँ से है? कस्टम?
एनपीके

हाँ, कस्टम। यह मूल रूप से प्रश्न से कोड है
एलेक्स34

2
OkHttpClient इसके बजाय काम नहीं करता है OKClient () का उपयोग करें। BDW अच्छा जवाब। धन्यवाद।
हर्षवर्धन त्रिवेदी

धन्यवाद :-)। OkHttp के सही उपयोग के साथ अपने उत्तर को संपादित किया।
user1007522

1
@MominAlAziz आप कैसे परिभाषित करते हैं NoConnectivityException, इसके आधार पर आप या तो इसका विस्तार कर सकते हैं या इसका विस्तार IOExceptionकर सकते हैंRuntimeException
AlexV

45

रेट्रोफिट के बाद से 1.8.0इसे हटा दिया गया है

retrofitError.isNetworkError()

आपको उपयोग करना है

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

}

कई प्रकार की त्रुटियां हैं जिन्हें आप संभाल सकते हैं:

NETWORK सर्वर से संचार करते समय एक IOException हुई, जैसे टाइमआउट, कोई कनेक्शन नहीं, आदि ...

CONVERSION एक निकाय को क्रमबद्ध करते समय एक अपवाद को फेंक दिया गया था।

HTTP एक गैर-200 HTTP स्टेटस कोड सर्वर से प्राप्त किया गया था जैसे 502, 503, आदि ...

UNEXPECTEDअनुरोध को निष्पादित करने का प्रयास करते समय एक आंतरिक त्रुटि हुई। इस अपवाद को फिर से फेंकना सबसे अच्छा अभ्यास है ताकि आपका एप्लिकेशन क्रैश हो जाए।


8
प्रयोग करने से बचें equalsचर से अधिक, हमेशा उपयोग CONSTANT.equals(variable)के बजाय संभव NullPointerException से बचने के लिए। या इस मामले में और भी बेहतर, enums स्वीकार == तुलना इसलिए error.getKind() == RetrofitError.Kind.NETWORKएक बेहतर दृष्टिकोण हो सकता है
MariusBudin

1
यदि आप NPEs और अन्य सिंटैक्स सीमाओं / दर्द से थक गए हैं तो जावा को कोटलिन से बदलें
लुई सीएडी

42

रेट्रोफ़िट 2 के साथ, हम अनुरोध भेजने से पहले नेटवर्क कनेक्टिविटी की जांच के लिए एक OkHttp इंटरसेप्टर कार्यान्वयन का उपयोग करते हैं। यदि कोई नेटवर्क नहीं है, तो एक अपवाद को उपयुक्त के रूप में फेंक दें।

यह एक विशेष रूप से रेट्रोफिट मारने से पहले नेटवर्क कनेक्टिविटी के मुद्दों को संभालने की अनुमति देता है।

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

3
यह त्रुटिपूर्ण है यदि आप हवाई जहाज मोड को चालू करते हैं तो इसे बंद कर दें क्योंकि आप केवल एक बार अवलोकन योग्य बनाने के बाद var सेट कर रहे हैं।
ओलिवर डिक्सन

3
तो आप OkHttpClient.Builder.addInterceptor(new ConnectivityInterceptor(HERE))यहाँ क्या होना चाहिए?
रुमिड

3
क्या आप उस कोड को शामिल कर सकते हैं ताकि लोगों को पूरी तस्वीर मिल सके?
ओलिवर डिक्सन

1
@ केविन मैं यह सुनिश्चित कर सकता हूं कि कनेक्शन उपलब्ध होने के बाद यह अपडेट होगा?
रुमिड

3
यह स्वीकृत उत्तर होना चाहिए। इसका और अधिक उदाहरण यहाँ: migapro.com/detect-offline-error-in-retrofit-2
j2emanue

35

@AlexV क्या आप सुनिश्चित हैं कि RetrofitError में एक कारण के रूप में एक टाइमआउट होता है (SocketTimeOutException जब getCause () कहा जाता है) जब कोई इंटरनेट कनेक्शन नहीं होता है?

जहाँ तक मुझे पता है कि जब कोई इंटरनेट कनेक्शन नहीं होता है तो RetrofitError में एक ConnectionException होती है।

यदि आप एक 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 ...]  
        }
    }

}

1
आपके द्वारा उपयोग किए जा सकने वाले रेट्रोफ़िट स्रोत में एक प्रदान किया गया ErrorHandler है। यदि आप स्वयं त्रुटि को नहीं संभालते हैं, तो रेट्रोफिट आपको [java.net.UnognHostException: RetrofitError देगा: होस्ट "example.com" को हल करने में असमर्थ: होस्टनाम से संबंधित कोई पता नहीं]
कोडवर्ड

1
@ कोड किया गया है ताकि isNetworkErrorमेजबान त्रुटि को हल करने में असमर्थ हो?
सर्वव्यापी

2
आप इसे अपने इंटरफ़ेस, क्लाइंट में कैसे लागू करेंगे? मेरा मतलब है, आप इस वर्ग को किससे जोड़ते हैं?
एफआरआर

23
कारण .isNetworkError () पदावनत किया गया है : उपयोगerror.getKind() == RetrofitError.Kind.NETWORK
ह्यूगो

6

रेट्रोफिट 1 के लिए

जब आपको 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!";
        }
    }
}

5

बस ऐसा करो तुम जैसे मुद्दों के लिए भी अधिसूचित किया जाएगा

UnknownHostException

,

SocketTimeoutException

और दूसरे।

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

2

आप इस कोड का उपयोग कर सकते हैं

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

अपने तरीकों में कार्यान्वयन

        @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);        
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.