723 Stimmen

Wie prüft man den Internetzugang auf Android? InetAddress schaltet nie ab

Ich habe eine AsyncTask das den Netzzugang zu einem Hostnamen überprüfen soll. Aber die doInBackground() ist nie zeitlich begrenzt. Hat jemand einen Hinweis?

public class HostAvailabilityTask extends AsyncTask<String, Void, Boolean> {

    private Main main;

    public HostAvailabilityTask(Main main) {
        this.main = main;
    }

    protected Boolean doInBackground(String... params) {
        Main.Log("doInBackground() isHostAvailable():"+params[0]);

        try {
            return InetAddress.getByName(params[0]).isReachable(30); 
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;       
    }

    protected void onPostExecute(Boolean... result) {
        Main.Log("onPostExecute()");

        if(result[0] == false) {
            main.setContentView(R.layout.splash);
            return;
        }

        main.continueAfterHostCheck();
    }   
}

7 Stimmen

Um zu prüfen, ob eine Internetverbindung besteht, ist es wahrscheinlich am zuverlässigsten, einen der großen Nameserver anzupingen, z. B. mit if(Runtime.getRuntime().exec("/system/bin/ping -c 1 8.8.8.8").waitFor()==0) ... . Siehe meine Antwort für eine schönere Implementierung dieser Funktion. Btw die akzeptierte Antwort (und viele andere hier) einfach nach einem Netzanschluss und nicht das Internet.

0 Stimmen

4 Stimmen

Verwenden Sie nicht die Ping-Methode, sondern eine HTTP-Überprüfung. ICMP wird in einigen Netzen blockiert, so dass Ping nicht funktioniert. Beispiel: Bei mir zu Hause funktioniert es einwandfrei, aber nicht, wenn ich mobile Daten im Netz von Vodafone (in Ungarn) verwende. Sie können die beiden Methoden auch kombinieren, aber seien Sie vorsichtig, denn waitFor() wartet etwa 20 Sekunden, auch wenn -w oder -W verwendet wird.

1048voto

gar Punkte 13483

Wenn sich das Gerät im Flugmodus befindet (oder vermutlich in anderen Situationen, in denen kein Netz verfügbar ist), cm.getActiveNetworkInfo() wird null Sie müssen also eine null prüfen.

Geändert ( Eddie's Lösung ) unten:

public boolean isOnline() {
    ConnectivityManager cm =
        (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getActiveNetworkInfo();
    return netInfo != null && netInfo.isConnectedOrConnecting();
}

Fügen Sie außerdem die folgende Berechtigung zur Datei AndroidManifest.xml :

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Ein weiterer kleiner Hinweis: Wenn Sie zu einem bestimmten Zeitpunkt unbedingt eine Netzwerkverbindung benötigen, ist es vielleicht besser, die netInfo.isConnected() statt netInfo.isConnectedOrConnecting . Ich denke, dies hängt jedoch vom jeweiligen Anwendungsfall ab.

116 Stimmen

Imo sollten und müssen Sie immer noch auf http-Timeout-Ausnahmen prüfen, da es Situationen geben kann, in denen ein Netzwerk verbunden ist, aber keine tatsächliche Internetverbindung besteht, weil der einzige Weg, darauf zuzugreifen, z. B. über VPN ist - auf diese Weise haben Sie z. B. eine WI-FI-Verbindung, aber keinen tatsächlichen Internetverkehr. Eine andere Situation ist ein Server-Hang-on. Dies sind 2 Probleme, die ich vor kurzem ausgeführt haben und Connection Manager ist nicht gonna dort helfen.

0 Stimmen

Ich habe isConnected und isConnectedOrConnection() verwendet und es gibt mir immer true seine Zeit nehmen, als ich jeden Rat erwartet "meine App verwendet Google Cloud Messaging und Web-Service"

0 Stimmen

@midnight u Recht gleiche Sache, die ich bin mit meinem Internet ist auf, aber Datenpakete sind nicht senden und recievint dann in dieser Situation, was können wir tun?

685voto

Levite Punkte 16245

Netzwerkanschluss / Internetzugang

  • isConnectedOrConnecting() (wird in den meisten Antworten verwendet) prüft auf alle Netzwerk Verbindung
  • Um zu erfahren, ob eines dieser Netze Internet Zugang, verwenden Sie eine der folgenden Möglichkeiten

A) Einen Server anpingen (einfach)

// ICMP 
public boolean isOnline() {
    Runtime runtime = Runtime.getRuntime();
    try {
        Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
        int     exitValue = ipProcess.waitFor();
        return (exitValue == 0);
    }
    catch (IOException e)          { e.printStackTrace(); }
    catch (InterruptedException e) { e.printStackTrace(); }

    return false;
}

+ könnte auf dem Hauptthread laufen

- funktioniert nicht auf einigen alten Geräten (Galays S3, etc.), es blockiert eine Weile, wenn kein Internet verfügbar ist.

B) Verbindung mit einem Socket im Internet (fortgeschritten)

// TCP/HTTP/DNS (depending on the port, 53=DNS, 80=HTTP, etc.)
public boolean isOnline() {
    try {
        int timeoutMs = 1500;
        Socket sock = new Socket();
        SocketAddress sockaddr = new InetSocketAddress("8.8.8.8", 53);

        sock.connect(sockaddr, timeoutMs);
        sock.close();

        return true;
    } catch (IOException e) { return false; }
}

+ sehr schnell (so oder so), funktioniert auf allen Geräten, sehr zuverlässig

- kann nicht auf dem UI-Thread ausgeführt werden

Das funktioniert sehr zuverlässig, auf jedem Gerät, und ist sehr schnell. Es muss allerdings in einem separaten Task laufen (z.B. ScheduledExecutorService o AsyncTask ).

Mögliche Fragen

  • Ist es wirklich schnell genug?

    Ja, sehr schnell ;-)

  • Gibt es keine andere zuverlässige Möglichkeit, das Internet zu überprüfen, als etwas im Internet zu testen?

    Soweit ich weiß, nicht, aber lassen Sie es mich wissen, und ich werde meine Antwort ändern.

  • Was ist, wenn der DNS nicht funktioniert?

    Google DNS (z.B.. 8.8.8.8 ) ist das größte öffentliche DNS der Welt. Im Jahr 2018 bearbeitete es über eine Billion Anfragen pro Tag [ 1 ]. Sagen wir einfach, Ihre App wäre wahrscheinlich nicht das Tagesgespräch.

  • Welche Berechtigungen sind erforderlich?

    <uses-permission android:name="android.permission.INTERNET" />

    Nur Internetzugang - Überraschung ^^ (Btw, hast du schon mal darüber nachgedacht, dass einige der hier vorgeschlagenen Methoden auch ohne diese Erlaubnis einen Fernkleber über den Internetzugang haben könnten?)

Extra: One-shot RxJava/RxAndroid Beispiel (Kotlin)

fun hasInternetConnection(): Single<Boolean> {
  return Single.fromCallable {
    try {
      // Connect to Google DNS to check for connection
      val timeoutMs = 1500
      val socket = Socket()
      val socketAddress = InetSocketAddress("8.8.8.8", 53)

      socket.connect(socketAddress, timeoutMs)
      socket.close()

      true
    } catch (e: IOException) {
      false
    }
  }
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
}

///////////////////////////////////////////////////////////////////////////////////
// Usage

    hasInternetConnection().subscribe { hasInternet -> /* do something */}

Extra: One-shot RxJava/RxAndroid Beispiel (Java)

public static Single<Boolean> hasInternetConnection() {
    return Single.fromCallable(() -> {
        try {
            // Connect to Google DNS to check for connection
            int timeoutMs = 1500;
            Socket socket = new Socket();
            InetSocketAddress socketAddress = new InetSocketAddress("8.8.8.8", 53);

            socket.connect(socketAddress, timeoutMs);
            socket.close();

            return true;
        } catch (IOException e) {
            return false;
        }
    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}

///////////////////////////////////////////////////////////////////////////////////
// Usage

    hasInternetConnection().subscribe((hasInternet) -> {
        if(hasInternet) {

        }else {

        }
    });

Extra: One-shot AsyncTask

Vorsicht! Dies ist ein weiteres Beispiel dafür, wie die Anfrage gestellt werden kann. Da jedoch AsyncTask ist veraltet und sollte durch das Thread-Scheduling Ihrer App, Kotlin Coroutines, Rx, ... ersetzt werden.

class InternetCheck extends AsyncTask<Void,Void,Boolean> {

    private Consumer mConsumer;
    public  interface Consumer { void accept(Boolean internet); }

    public  InternetCheck(Consumer consumer) { mConsumer = consumer; execute(); }

    @Override protected Boolean doInBackground(Void... voids) { try {
        Socket sock = new Socket();
        sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
        sock.close();
        return true;
    } catch (IOException e) { return false; } }

    @Override protected void onPostExecute(Boolean internet) { mConsumer.accept(internet); }
}

///////////////////////////////////////////////////////////////////////////////////
// Usage

    new InternetCheck(internet -> { /* do something with boolean response */ });

0 Stimmen

Ich kann dies nicht für jede REST-Anfrage verwenden, wie bei OkHttp3 Caching Interceptors. Dies wird meine Antwortzeit erhöhen.

1 Stimmen

Dies ist nicht geräteübergreifend und sollte NICHT für die Produktion verwendet werden.

0 Stimmen

@Levit : Gibt es eine Möglichkeit, eine Zeitüberschreitung für diese Anfrage einzustellen, oder ist es erforderlich, eine Zeitüberschreitung für diese Anfrage einzustellen?

297voto

Eddie Punkte 9106

Es muss nicht kompliziert sein. Die einfachste und einfachste Methode ist die Verwendung von ACCESS_NETWORK_STATE Erlaubnis und machen Sie einfach eine verbundene Methode

public boolean isOnline() {
    ConnectivityManager cm =
        (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

    return cm.getActiveNetworkInfo() != null && 
       cm.getActiveNetworkInfo().isConnectedOrConnecting();
}

Sie können auch Folgendes verwenden requestRouteToHost wenn Sie einen bestimmten Host und eine bestimmte Verbindungsart (Wifi/Mobilfunk) im Sinn haben.

Sie benötigen außerdem:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

in Ihrem Android-Manifest.

82 Stimmen

Es ist besser, auf der Ebene cm.getActiveNetworkInfo() eine Null-Prüfung durchzuführen, wenn kein aktives Netz verfügbar ist.

0 Stimmen

Siehe stackoverflow.com/a/11691676/1979773 für eine genauere Erläuterung von requestRouteToHost()

0 Stimmen

Ich musste den Kontext hinzufügen, in context.getSystemService oder es funktioniert nicht. Ich habe meinen Hinweis hier androidhive.info/2012/07/

63voto

azelez Punkte 2471

Um die getActiveNetworkInfo() funktionieren soll, müssen Sie dem Manifest Folgendes hinzufügen.

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

0 Stimmen

Dies sollte definitiv unter der richtigen Antwort stehen (habe zu viel Zeit damit verschwendet, herauszufinden, was zum Teufel falsch ist).

2 Stimmen

Die Berechtigung INTERNET ist hierfür NICHT erforderlich, sondern nur ACCESS_NETWORK_STATE. INTERNET wird nur benötigt, wenn Sie tatsächlich Verbindungen zu entfernten Standorten herstellen und nicht den Status des Funkgeräts abfragen.

5 Stimmen

Ihre Antwort ist im Moment keine richtige Antwort, sondern nur eine relativ unbedeutende Ergänzung zu anderen Antworten. Würde Ihre Antwort einen Sinn ergeben, wenn alle anderen Antworten nicht da wären? Nicht wirklich. Wenn das der Fall ist, ist es besser, Ihre Antwort mit einem Code zu erweitern, oder Ihre Antwort zu entfernen und die Informationen in einer anderen Antwort hinzuzufügen (Sie verlieren dabei kein Ansehen)

48voto

Chinmay Kanchi Punkte 58341

Werfen Sie einen Blick auf die Klasse ConnectivityManager. Sie können diese Klasse verwenden, um Informationen über die aktiven Verbindungen auf einem Host zu erhalten. http://developer.Android.com/reference/Android/net/ConnectivityManager.html

EDIT: Sie können verwenden

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .getNetworkInfo(ConnectivityManager.TYPE_MOBILE) 

oder

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .getNetworkInfo(ConnectivityManager.TYPE_WIFI) 

und analysiert das DetailedState-Enum des zurückgegebenen NetworkInfo-Objekts

EDIT EDIT: Um herauszufinden, ob Sie auf einen Host zugreifen können, können Sie

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .requestRouteToHost(TYPE_WIFI, int hostAddress)

Offensichtlich verwende ich Context.getSystemService(Context.CONNECTIVITY_SERVICE) als Proxy, um zu sagen

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

0 Stimmen

Ich bin mir nicht sicher, aber das scheint ein Code zu sein, der testet, welche Art von Netzwerkverbindung ich gerade habe. Z.B. im auf WiFi, gibt es keine Garantie, dass Sie zu Hause WiFi-Router mit internett... verbunden ist, um zu überprüfen, dass Sie tatsächlich eine Anfrage an einen internetserver tun müssen...

1 Stimmen

Es gab einen Fehler im Abschnitt EDIT EDIT, ich hatte den Aufruf requestRouteToHost() ausgelassen. Lesen Sie die Antwort jetzt erneut :)

0 Stimmen

RequestRouteToHost ist veraltet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X