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.

11voto

Hawklike Punkte 615

Kotlin und Koroutinen

Ich habe die Funktion in eine ViewModel die die viewModelScope . Verwendung einer beobachtbaren LiveData Ich informiere eine Aktivität über die Verbindung.

ViewModel

 fun checkInternetConnection(timeoutMs: Int) {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                val socket = Socket()
                val socketAddress = InetSocketAddress("8.8.8.8", 53)

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

                _connection.postValue(true)
            }
            catch(ex: IOException) {
                _connection.postValue(false)
            }
        }
    }

 private val _connection = MutableLiveData<Boolean>()
 val connection: LiveData<Boolean> = _connection

Tätigkeit

 private fun checkInternetConnection() {
     viewModel.connection.observe(this) { hasInternet ->
         if(!hasInternet) {
             //hasn't connection
         }
         else {
            //has connection
         }
     }
  }

0 Stimmen

Funktioniert nicht, ruft nicht mehr an

0 Stimmen

@AnshulTyagi Was funktioniert nicht? Haben Sie die Methode tatsächlich aus dem View-Modell in Ihrer Aktivität aufgerufen? Wenn Sie die Internetverbindung mehrfach prüfen wollen, fügen Sie eine Schleife im View Model hinzu (while, repeat, etc.) und aktualisieren Sie die _connection entsprechend variabel.

0 Stimmen

@Hawklike Ich habe es nicht verwendet mit ViewModel ou LiveData aber mit einfachen Koroutinen, selbst wenn Sie repeat ou while Schleife nach einer Ausnahme scheint es, dass dieser Code den übergeordneten Coroutine-Kontext abbrechen wird.

9voto

Jared Burrows Punkte 52572

Hier ist die Methode, die ich verwende:

public boolean isNetworkAvailable(final Context context) {
    return ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo() != null;
}

Noch besser ist es, sich zu vergewissern, dass es "angeschlossen" ist:

public boolean isNetworkAvailable(final Context context) {
    final ConnectivityManager connectivityManager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
    return connectivityManager.getActiveNetworkInfo() != null && connectivityManager.getActiveNetworkInfo().isConnected();
}

Im Folgenden wird beschrieben, wie die Methode anzuwenden ist:

if (isNetworkAvailable(context)) {
    // code here
} else {
    // code
}

Erlaubnis erforderlich:

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

https://stackoverflow.com/a/16124915/950427

8voto

user1528493 Punkte 431

Ein wichtiger Anwendungsfall auf mobilen Geräten, um sicherzustellen, dass eine tatsächliche Verbindung besteht. Dies ist ein häufiges Problem, wenn ein mobiler Benutzer ein Wifi-Netzwerk mit einem "Captive Portal" betritt, bei dem er sich anmelden muss. Ich verwende diese Blockierfunktion im Hintergrund, um sicherzustellen, dass eine Verbindung besteht.

/*
 * Not Thread safe. Blocking thread. Returns true if it
 * can connect to URL, false and exception is logged.
 */
public boolean checkConnectionHttps(String url){
    boolean responded = false;
    HttpGet requestTest = new HttpGet(url);
    HttpParams params = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(params, 3000);
    HttpConnectionParams.setSoTimeout(params, 5000);
    DefaultHttpClient client = new DefaultHttpClient(params);
    try {
        client.execute(requestTest);
        responded = true;
    } catch (ClientProtocolException e) {
        Log.w(MainActivity.TAG,"Unable to connect to " + url + " " + e.toString());
    } catch (IOException e) {
        Log.w(MainActivity.TAG,"Unable to connect to " + url + " " + e.toString());
        e.printStackTrace();
    }
    return responded;
}

5 Stimmen

+1 für die tatsächliche Überprüfung der Ende-zu-Ende-Konnektivität. Für die "Captive Portal"-Situation habe ich jedoch festgestellt, dass viele den obigen Test bestehen, auch wenn man sich nicht angemeldet hat - man erhält die Anmeldeseite und eine 200er-Antwort, egal nach welcher URL man fragt. Ich versuche also, eine Seite auf meiner eigenen Domäne aufzurufen, von der ich weiß, dass sie nicht existiert, und stelle sicher, dass ich eine 404 erhalte. Alternativ können Sie auch eine bekannte Seite aufrufen, sicherstellen, dass Sie eine 200er-Antwort erhalten, und den zurückgegebenen Inhalt überprüfen, um sicherzustellen, dass er Ihren Erwartungen entspricht.

8voto

Nickolaus Punkte 4652

Von allem, was ich bisher gesehen habe, sollte das der kürzeste und sauberste Weg sein:

public final static boolean isConnected( Context context )
{   
   final ConnectivityManager connectivityManager = 
         (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );  
   final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();    
   return networkInfo != null && networkInfo.isConnected();
}

PS: Diese Methode pingt keinen Host an, sondern prüft nur den Verbindungsstatus. Wenn also Ihr Router keine Internetverbindung hat und Ihr Gerät mit ihm verbunden ist, würde diese Methode Folgendes zurückgeben wahr obwohl Sie kein Internet haben.
Für einen tatsächlichen Test würde ich empfehlen, eine HttpHead-Anfrage auszuführen (z.B. an www.google.com) und überprüfen Sie den Status, wenn seine 200 OK alles in Ordnung ist und Ihr Gerät eine Internetverbindung hat.

0 Stimmen

Ich wollte diese Methode in eine globale Klasse einfügen, also musste ich diese Version verwenden, damit ich den Kontext von der Aktivität, aus der ich sie aufrufe, übergeben kann. Vielen Dank!

7voto

selva_pollachi Punkte 4117

Das funktioniert bei mir. Probieren Sie es aus.

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    try {
        URL url = new URL("http://stackoverflow.com/posts/11642475/edit" );
        //URL url = new URL("http://www.nofoundwebsite.com/" );
        executeReq(url);
        Toast.makeText(getApplicationContext(), "Webpage is available!", Toast.LENGTH_SHORT).show();
    }
    catch(Exception e) {
        Toast.makeText(getApplicationContext(), "oops! webpage is not available!", Toast.LENGTH_SHORT).show();
    }
}

private void executeReq(URL urlObject) throws IOException
{
    HttpURLConnection conn = null;
    conn = (HttpURLConnection) urlObject.openConnection();
    conn.setReadTimeout(30000);//milliseconds
    conn.setConnectTimeout(3500);//milliseconds
    conn.setRequestMethod("GET");
    conn.setDoInput(true);

    // Start connect
    conn.connect();
    InputStream response =conn.getInputStream();
    Log.d("Response:", response.toString());
}}

0 Stimmen

Diese Antwort kann jetzt nicht mehr funktionieren, da wir im Hauptthread nicht mehr auf das Netzwerk zugreifen können.

1 Stimmen

Ich meine, ab API-Ebene 11 funktioniert das nicht. Grund: developer.Android.com/reference/Android/os/ . Wenn es bei Ihnen funktioniert, bedeutet das, dass Sie diesen Code auf einem alten Android-Gerät ausführen. (vor GB).

0 Stimmen

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder() .permitAll().build(); StrictMode.setThreadPolicy(policy); Fügen Sie diese beiden Zeilen in Ihr Programm ein, um eine Ausnahme für den Hauptthread im Netzwerk zu vermeiden

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