Come controllare l'accesso a Internet su Android? InetAddress non scade mai


658

Ho ottenuto un AsyncTaskche dovrebbe controllare l'accesso di rete a un nome host. Ma doInBackground()non è mai scaduto. Qualcuno ha un indizio?

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

5
Per verificare la presenza di una connessione Internet, probabilmente il modo più affidabile sarebbe quello di eseguire il ping di uno dei principali server dei nomi, ad esempio con questo if(Runtime.getRuntime().exec("/system/bin/ping -c 1 8.8.8.8").waitFor()==0) .... Vedi la mia risposta per una migliore implementazione di questo. Tra la risposta accettata (e molti altri qui) basta cercare una connessione di rete , non Internet.
Levita,


4
Non utilizzare il metodo ping, utilizzare invece un controllo HTTP. ICMP è bloccato su alcune reti, quindi il ping non funzionerà. Ad esempio: funziona perfettamente sul mio wifi di casa, ma non quando uso i dati mobili sulla rete di Vodafone (in Ungheria). Oppure combina i 2 metodi come fallback, ma fai attenzione perché waitFor () attenderà circa 20 secondi anche se si utilizza -w o -W.
Tamás Bolvári,

Dai un'occhiata a questo: stackoverflow.com/a/39766506/3806413
0xAliHn

@ TamásBolvári: Ancora meglio sarebbe affrontarlo a livello di PCC. Il che dovrebbe avvicinarti alla velocità di un ICMP, con l'affidabilità di una richiesta HTTP. Ho modificato la "risposta ping" di conseguenza.
Levita,

Risposte:


556

Connessione di rete / accesso a Internet

  • isConnectedOrConnecting()(utilizzato nella maggior parte delle risposte) verifica l'eventuale connessione di rete
  • Per sapere se una di queste reti ha accesso a Internet , utilizzare una delle seguenti opzioni

A) Ping a Server (facile)

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

+ potrebbe essere eseguito sul thread principale

- non funziona su alcuni vecchi dispositivi (Galays S3, ecc.), si blocca per un po 'se non è disponibile internet.

B) Connessione a una presa su Internet (avanzata)

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

+molto veloce (in entrambi i casi), funziona su tutti i dispositivi, molto affidabile

- non può essere eseguito sul thread dell'interfaccia utente

Funziona in modo molto affidabile, su ogni dispositivo ed è molto veloce. Deve tuttavia essere eseguito in un'attività separata (ad es. ScheduledExecutorServiceO AsyncTask).

Possibili domande

  • È davvero abbastanza veloce?

    Sì, molto velocemente ;-)

  • Non esiste un modo affidabile per controllare Internet, oltre a provare qualcosa su Internet?

    Non per quanto ne so, ma fammi sapere, e modificherò la mia risposta.

  • Cosa succede se il DNS è inattivo?

    Google DNS (ad es. 8.8.8.8) È il più grande DNS pubblico al mondo. A partire dal 2013 ha servito 130 miliardi di richieste al giorno. Diciamo solo che la tua app probabilmente non sarebbe il discorso del giorno.

  • Quali autorizzazioni sono necessarie?

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

    Solo accesso a Internet - sorpresa ^^ (A proposito, hai mai pensato, come alcuni dei metodi suggeriti qui potrebbero anche avere una colla remota sull'accesso a Internet, senza questa autorizzazione?)

 

Extra: One-shot AsyncTaskEsempio

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

Extra: esempio One-shot RxJava/RxAndroid(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 */}

22
Questa è una grande tranquillità di codice! L'ho trovato molto utile su dispositivi che utilizzano carte prepagate! Quando finiscono i soldi, hanno accesso a Internet disponibile, ma niente internet. Quindi non basta controllare la connettività. GRAZIE!
Blejzer,

10
Tieni presente che questo approccio è bloccante, quindi non dovresti eseguirlo nell'interfaccia utente
Sergii,

36
@Levit Questa dovrebbe essere la risposta accettata. Sopra la risposta controlla solo Rete n NON CONNESSIONE INTERNET . E sì, questo è molto veloce. Grazie. Quindi voto positivo.
Roon13

9
Questa soluzione non funziona per tutti i dispositivi. Alcuni dispositivi restituiscono sempre 2 come indicato da @Salmaan. I dispositivi che ho testato avevano una connessione Internet e il target del ping è il server DNS di Google, che risponde alle richieste di ping. Penso che alcuni venditori non consentano richieste di ping. Ad esempio, ho testato con un tablet Samsung 10.1 (4.3) e la soluzione non funziona. Quando eseguo il comando ping tramite l'utilità della riga di comando, viene visualizzato un errore di autorizzazione. Inoltre, il comando non funziona sugli emulatori. Fai attenzione usando questa soluzione.
Eren Yilmaz,

9
Questo approccio non funziona su tutti i telefoni. Non funziona, ad esempio, su Samsung Galaxy S3. Vedi qui: Perché il ping funziona su alcuni dispositivi e non su altri?
Adil Hussain,

1032

Se il dispositivo è in modalità aereo (o presumibilmente in altre situazioni in cui non è disponibile una rete), cm.getActiveNetworkInfo()lo sarà null, quindi è necessario aggiungere un nullcontrollo.

Modificato ( soluzione di Eddie ) di seguito:

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

Aggiungere anche la seguente autorizzazione a AndroidManifest.xml:

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

Un altro piccolo punto, se hai assolutamente bisogno di una connessione di rete in un dato momento, potrebbe essere meglio usare netInfo.isConnected()piuttosto che netInfo.isConnectedOrConnecting. Immagino che questo dipenda dal singolo caso d'uso.


109
imo dovresti e dovresti verificare le eccezioni di timeout http poiché potrebbero esserci situazioni in cui una rete è connessa ma non ci sarebbe una vera connessione a Internet perché l'unico modo per accedervi è attraverso, ad esempio, VPN - in questo modo, per ad esempio, connessione WI-FI ma nessun traffico Internet effettivo. Un'altra situazione è un aggancio del server. Questi sono 2 problemi che ho eseguito di recente e la gestione connessione non ti aiuterà.
mezzanotte

21
Sono d'accordo con mezzanotte e Pintu, questa risposta non dovrebbe essere la risposta accettata, non ha nulla a che fare con il controllo se sei su Internet. Ad esempio, se il telefono è collegato a una rete WiFi con un portale captive, come in un hotel, questa funzione restituirà erroneamente true. La risposta corretta è eseguire il ping di un server su Internet pubblico.
miguel

9
quando non c'è internet funzionante per il mio router, se mi collego al router tramite wifi, il codice sopra riportato ritorna vero. Ma non dovrebbe essere vero? Potete aiutarmi
MoHaN K RaJ,

5
Ho dovuto aggiungere il contesto, context.getSystemServiceo non funziona. Ho avuto la mia idea qui androidhive.info/2012/07/…
Francisco Corrales Morales,

1
Bel modo di verificare la disponibilità della rete. Ma come controllare l'accesso a Internet?
Tamás Bolvári,

296

Non è necessario essere complessi. Il modo più semplice e quadro è utilizzare l' ACCESS_NETWORK_STATEautorizzazione e creare semplicemente un metodo connesso

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

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

Puoi anche usarlo requestRouteToHostse hai in mente un host particolare e un tipo di connessione (wifi / mobile).

Avrai anche bisogno di:

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

nel tuo manifest Android.


82
è meglio fare un controllo nullo a livello di cm.getActiveNetworkInfo () ha gettato un null se non era disponibile alcuna rete attiva.
Samuel,

vedi stackoverflow.com/a/11691676/1979773 per un exaplanation profonda circa requestRouteToHost ()
Spartako

Ho dovuto aggiungere il contesto, context.getSystemServiceo non funziona. Ho avuto la mia idea qui androidhive.info/2012/07/…
Francisco Corrales Morales,

9
Questa soluzione tornerà vera se sei connesso a un hotspot WiFi, anche se questo hotspot NON ha connettività Internet.
Josh,


63

Per mettersi getActiveNetworkInfo()al lavoro è necessario aggiungere quanto segue al manifest.

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

Questo dovrebbe essere sicuramente sotto la risposta corretta (sprecato troppo tempo a capire cosa diavolo è sbagliato).
Indrek Kõue,

2
L'autorizzazione INTERNET NON è necessaria per questo, solo ACCESS_NETWORK_STATE. INTERNET è necessario solo se si stanno effettivamente effettuando connessioni a posizioni remote, senza interrogare lo stato della radio del dispositivo.
Tom,

3
La tua risposta non è attualmente una risposta, è solo un'aggiunta relativamente minore ad altre risposte. Se tutte le altre risposte non fossero qui, la tua risposta avrebbe senso? Non proprio. Perché se è meglio espandere la tua risposta con il codice su come usarla, o rimuovere la tua risposta e aggiungere le informazioni in un'altra risposta (non perderai alcuna reputazione)
Tim

Fare attenzione getActiveNetworkInfo()è deprecato nel livello API 29.
StackTranslate.it

46

Dai un'occhiata alla classe ConnectivityManager. È possibile utilizzare questa classe per ottenere informazioni sulle connessioni attive su un host. http://developer.android.com/reference/android/net/ConnectivityManager.html

EDIT: è possibile utilizzare

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

o

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

e analizza l'enum DettagliatoState dell'oggetto NetworkInfo restituito

MODIFICA MODIFICA: per scoprire se è possibile accedere a un host, è possibile utilizzare

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

Ovviamente, sto usando Context.getSystemService (Context.CONNECTIVITY_SERVICE) come proxy per dire

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

Non sono sicuro, ma questo sembra un codice per testare il tipo di connessione di rete attualmente attiva. Ad esempio, sono su WiFi, non esiste alcuna garanzia che il tuo router wifi domestico sia collegato a Internet ... per verificare che tu debba effettivamente fare una richiesta a un
server

1
Si è verificato un errore nella sezione EDIT EDIT, avevo lasciato fuori la chiamata requestRouteToHost ().
Rileggi

requestRouteToHost è stato deprecato.
Jahaziel,

46

controlla questo codice ... ha funzionato per me :)

public static void isNetworkAvailable(final Handler handler, final int timeout) {
    // ask fo message '0' (not connected) or '1' (connected) on 'handler'
    // the answer must be send before before within the 'timeout' (in milliseconds)

    new Thread() {
        private boolean responded = false;   
        @Override
        public void run() { 
            // set 'responded' to TRUE if is able to connect with google mobile (responds fast) 
            new Thread() {      
                @Override
                public void run() {
                    HttpGet requestForTest = new HttpGet("http://m.google.com");
                    try {
                        new DefaultHttpClient().execute(requestForTest); // can last...
                        responded = true;
                    } 
                    catch (Exception e) {
                    }
                } 
            }.start();

            try {
                int waited = 0;
                while(!responded && (waited < timeout)) {
                    sleep(100);
                    if(!responded ) { 
                        waited += 100;
                    }
                }
            } 
            catch(InterruptedException e) {} // do nothing 
            finally { 
                if (!responded) { handler.sendEmptyMessage(0); } 
                else { handler.sendEmptyMessage(1); }
            }
        }
    }.start();
}

Quindi, definisco il gestore:

Handler h = new Handler() {
    @Override
    public void handleMessage(Message msg) {

        if (msg.what != 1) { // code if not connected

        } else { // code if connected

        }   
    }
};

... e avvia il test:

isNetworkAvailable(h,2000); // get the answser within 2000 ms

3
Che cos'è Google non funziona? Ciò richiede anche l'autorizzazione INTERNET, che non è necessaria per l'attività specificata. Infine, ciò consuma dati (anche se insignificanti). Sembra proprio un tale kludge.
Tom,

28
Per essere onesti, questa è probabilmente l'unica risposta corretta. Gli altri esempi mostrano semplicemente se è disponibile una connessione di rete e / o se esiste una connessione a quella rete, ma non rispondere alla domanda se quella rete può effettivamente effettuare anche una connessione remota (ad esempio a un sito Web). Quindi questo risponde ai manifesti Q, e le altre risposte no
slinden77

2
@dmmh Sì, è purtroppo vero da quello che ho visto con le API di Android. Forse un semplice ping potrebbe essere migliore, stackoverflow.com/questions/3905358/… . Se fossi davvero preoccupato, potresti anche includere un elenco di IP per il ping, perché mentre c'è una probabilità molto piccola che Google scenderà mai, c'è anche una possibilità ancora più piccola che Google, Bing e Yahoo scenderanno lo stesso giorno . Solo i miei pensieri.
Tom,

10
Non ha senso fare questo controllo. Se hai intenzione di spendere il tempo di sistema e le risorse di rete per connetterti a Google, avresti potuto spenderli invece di connetterti alla risorsa che ti interessa davvero.
Benjamin,

16
In Cina Google è stato bloccato !!
Anthone,

26

Trovato e modificato (!) Da questo link :

Nel tuo file manifest aggiungi almeno:

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

Probabilmente hai già l'autorizzazione INTERNET se accedi. Quindi una funzione booleana che consente di verificare la connettività è:

private boolean checkInternetConnection() {
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    // test for connection
    if (cm.getActiveNetworkInfo() != null
            && cm.getActiveNetworkInfo().isAvailable()
            && cm.getActiveNetworkInfo().isConnected()) {
        return true;
    } else {
        Log.v(TAG, "Internet Connection Not Present");
        return false;
    }
}

18

Ho creato questo codice, è il più semplice ed è solo un valore booleano. chiedendoif(isOnline()){

Si ottiene se esiste una connessione e se può connettersi a una pagina il codice di stato 200(connessione stabile).

Assicurati di aggiungere il corretto INTERNETe le ACCESS_NETWORK_STATEautorizzazioni.

public boolean isOnline() {
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getActiveNetworkInfo();
    if (netInfo != null && netInfo.isConnected()) {
        try {
            URL url = new URL("http://www.google.com");
            HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
            urlc.setConnectTimeout(3000);
            urlc.connect();
            if (urlc.getResponseCode() == 200) {
                return new Boolean(true);
            }
        } catch (MalformedURLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    return false;
}

6
Forse dovresti sostituire 200 con HttpURLConnection.HTTP_OK
Yash il

5
Che cosa succede se Google non funziona?
Yauraw Gadav,

12

Funziona per me:

Per verificare la disponibilità della rete:

private Boolean isNetworkAvailable() {
ConnectivityManager connectivityManager 
      = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting();}

Per verificare l'accesso a Internet:

public Boolean isOnline() {
    try {
        Process p1 = java.lang.Runtime.getRuntime().exec("ping -c 1 www.google.com");
        int returnVal = p1.waitFor();
        boolean reachable = (returnVal==0);
        return reachable;
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return false;
}

questa è un'ottima soluzione per verificare se un server è installato, funziona davvero bene. Grazie!
Williew,

1
isOnline () non dovrebbe essere eseguito sul thread principale, come se ci fosse un segnale wi-fi ma nessuna connessione internet ci vorrà troppo tempo e bloccherà il thread principale.
impazzito il

9

C'è più di un modo

Primo, il modo più breve ma inefficiente

È necessaria solo l'autorizzazione dello stato della rete

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

Quindi questo metodo,

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

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

        return isConnected;

    }

Come visto nelle risposte ConnectivityManagerè una soluzione, l'ho appena aggiunto all'interno di un metodo, questo è un metodo semplificato che tutto usa
ConnectivityManagerrestituisce vero se c'è un accesso alla rete non l'accesso a Internet, significa che se il tuo WiFi è collegato a un router ma il router non ha Internet restituisce true, controlla la disponibilità della connessione

Secondo, modo efficiente

Stato della rete e autorizzazioni Internet necessarie

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

Quindi questa classe,

 public class CheckInternetAsyncTask extends AsyncTask<Void, Integer, Boolean> {

        private Context context;

        public CheckInternetAsyncTask(Context context) {
            this.context = context;
        }

        @Override
        protected Boolean doInBackground(Void... params) {

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

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


            if (isConnected) {
                try {
                    HttpURLConnection urlc = (HttpURLConnection)
                            (new URL("http://clients3.google.com/generate_204")
                                    .openConnection());
                    urlc.setRequestProperty("User-Agent", "Android");
                    urlc.setRequestProperty("Connection", "close");
                    urlc.setConnectTimeout(1500);
                    urlc.connect();
                    if (urlc.getResponseCode() == 204 &&
                            urlc.getContentLength() == 0)
                        return true;

                } catch (IOException e) {
                    Log.e("TAG", "Error checking internet connection", e);
                    return false;
                }
            } else {
                Log.d("TAG", "No network available!");
                return false;
            }


            return null;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            Log.d("TAG", "result" + result);

            if(result){
                // do ur code
            }

        }


    }

Chiamata CheckInternetAsyncTask

new CheckInternetAsyncTask(getApplicationContext()).execute();

Alcune spiegazioni: -

  • devi controllare Internet AsyncTask, altrimenti android.os.NetworkOnMainThreadExceptionin alcuni casi può essere lanciato

  • ConnectivityManager utilizzato per verificare l'accesso alla rete se la richiesta di invio true (ping)

  • Richiesta di invio a http://clients3.google.com/generate_204, Questo noto URL restituisce una pagina vuota con uno stato HTTP 204 questo è più veloce ed efficiente di http://www.google.com, leggi questo . se si dispone di un sito Web, è preferibile inserire il sito Web anziché Google, solo se lo si utilizza all'interno dell'app

  • Il timeout può essere modificato nell'intervallo (20 ms -> 2000 ms), di solito viene utilizzato 1500 ms


2
Ottima domanda, è triste che non hai più punti. Questa deve essere la risposta corretta.
Jhon Fredy Trujillo Ortega,

Sono nuovo di Android. tuttavia, questa è una risposta ben coperta e attira più attenzione @ 7569106
Mazen Embaby,

1
migliore e completa risposta, grazie. se qualcuno ha un sito web nota che tale condizione deve gradire urlc.getResponseCode () == 200 e non è necessario controllare urlc.getContentLength () == 0
AREF

la tua seconda opzione si blocca, non so perché
nafees si è verificato il

blocca l'applicazione
nafees il

8

Di tutto ciò che ho visto finora il modo più breve e pulito dovrebbe essere:

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: Questo non esegue il ping di alcun host, controlla solo lo stato della connessione, quindi se il tuo router non ha una connessione Internet e il tuo dispositivo è connesso ad esso questo metodo tornerà vero anche se non hai Internet.
Per un test effettivo, consiglierei di eseguire una richiesta HttpHead (ad es. Su www.google.com) e di controllare lo stato, se è 200 OK tutto va bene e il tuo dispositivo ha una connessione Internet.


Volevo mettere questo metodo in una classe globale, quindi ho dovuto usare questa versione in modo da poter passare il contesto dall'attività da cui lo chiamavo. Grazie!
RyanG,

8

Ecco il metodo che uso:

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

Ancora meglio, controlla per assicurarti che sia "connesso":

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

Ecco come utilizzare il metodo:

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

Autorizzazione necessaria:

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

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


7

Un caso d'uso importante sui dispositivi mobili per garantire l'esistenza di una connessione effettiva. Questo è un problema comune quando un utente mobile accede a una rete Wifi con un "Captive Portal", in cui deve accedere. Uso questa funzione di blocco in background per garantire l'esistenza di una connessione.

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

3
+1 per il controllo effettivo della connettività end-to-end. Per la situazione del "Captive Portal", tuttavia, ho scoperto che molti supereranno il test di cui sopra anche se non si è effettuato l'accesso: si ottiene la pagina di accesso e una risposta 200 indipendentemente dall'URL richiesto. Quindi tento di colpire una pagina sul mio dominio che so non esiste e di assicurarmi di ottenere un 404. In alternativa, potresti colpire una pagina esistente conosciuta, assicurarti di ottenere un 200 e controllare il contenuto che viene restituito per assicurarsi che sia quello che ti aspetti.
GreyBeardedGeek

6

Puoi iterare su tutte le connessioni di rete e verificare se esiste almeno una connessione disponibile:

public boolean isConnected() {
    boolean connected = false;

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

    if (cm != null) {
        NetworkInfo[] netInfo = cm.getAllNetworkInfo();

        for (NetworkInfo ni : netInfo) {
            if ((ni.getTypeName().equalsIgnoreCase("WIFI")
                    || ni.getTypeName().equalsIgnoreCase("MOBILE"))
                    && ni.isConnected() && ni.isAvailable()) {
                connected = true;
            }

        }
    }

    return connected;
}

6

Per me non è stata una buona pratica controllare lo stato della connessione nella classe Activity, perché

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

dovrebbe essere chiamato lì, oppure è necessario trasferire l'istanza di attività (contesto) alla classe del gestore di connessione per poter verificare lo stato della connessione lì Quando nessuna connessione disponibile (wifi, rete) prendo l' eccezione UnknownHostException :

JSONObject jObj = null;
Boolean responded = false;
HttpGet requestForTest = new HttpGet("http://myserver.com");
try {
    new DefaultHttpClient().execute(requestForTest);
    responded = true;
} catch (UnknownHostException e) {
    jObj = new JSONObject();
    try {
        jObj.put("answer_code", 1);
        jObj.put("answer_text", "No available connection");
    } catch (Exception e1) {}
    return jObj;
} catch (IOException e) {
    e.printStackTrace();
}

In questo modo posso gestire questo caso insieme agli altri casi della stessa classe (il mio server risponde sempre con una stringa json)


6

Funziona per me. Provalo.

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

Questa risposta non può funzionare ora, dal momento che non possiamo accedere alla rete sul thread principale ora.
正宗 白 布鞋

1
Voglio dire dal livello API 11, questo non funziona. Motivo: developer.android.com/reference/android/os/… . Se funziona per te, significa che stai eseguendo questo codice sul vecchio dispositivo Android. (prima di GB).
正宗 白 布鞋

Politica StrictMode.ThreadPolicy = new StrictMode.ThreadPolicy.Builder () .permitAll (). Build (); StrictMode.setThreadPolicy (la politica); aggiungi queste due righe due al tuo programma per evitare l'eccezione del thread principale della rete
selva_pollachi,

Ok, non dovrei dire che non può funzionare, dovrei dire che può funzionare (dalla vecchia versione di destinazione o dalla configurazione di Strictmode) ma è scoraggiato. Ciò può causare ANR facilmente. (Con una configurazione di timeout così elevata in httpurlconnection)
正宗 白 布鞋

ya..hai ragione .. ho messo questo perché anche questo è uno dei modi.
selva_pollachi,

6

Questo metodo ti dà la possibilità di un metodo molto veloce (per feedback in tempo reale) o un metodo più lento (per controlli una tantum che richiedono affidabilità)

public boolean isNetworkAvailable(bool SlowButMoreReliable) {
    bool Result = false; 
    try {
        if(SlowButMoreReliable){
            ConnectivityManager MyConnectivityManager = null;
            MyConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

            NetworkInfo MyNetworkInfo = null;
            MyNetworkInfo = MyConnectivityManager.getActiveNetworkInfo();

            Result = MyNetworkInfo != null && MyNetworkInfo.isConnected();

        } else
        {
            Runtime runtime = Runtime.getRuntime();
            Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");

            int i = ipProcess.waitFor();

            Result = i== 0;

        }

    } catch(Exception ex)
    {
        //Common.Exception(ex); //This method is one you should have that displays exceptions in your log
    }
    return Result;
}

5

Sto usando questo codice invece di InetAddress:

    try {

        URL url = new URL("http://"+params[0]);

        HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
        urlc.setRequestProperty("User-Agent", "Android Application:"+Z.APP_VERSION);
        urlc.setRequestProperty("Connection", "close");
        urlc.setConnectTimeout(1000 * 30); // mTimeout is in seconds
        urlc.connect();
        if (urlc.getResponseCode() == 200) {
            Main.Log("getResponseCode == 200");
            return new Boolean(true);
        }
    } catch (MalformedURLException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Sarebbe bello se avessi chiarito se IOException non significa alcuna connessione a Internet e quanto possa essere affidabile.
Milad.Nozari,

5

Non è complesso controllare lo stato della connettività di rete / Internet Android. La DetectConnectionclasse seguente ti aiuterà a verificare questo stato:

import android.content.Context;
import android.net.ConnectivityManager;

public class DetectConnection {
    public static boolean checkInternetConnection(Context context) {
        ConnectivityManager con_manager = (ConnectivityManager) context
                                .getSystemService(Context.CONNECTIVITY_SERVICE);

        if (con_manager.getActiveNetworkInfo() != null
            && con_manager.getActiveNetworkInfo().isAvailable()
            && con_manager.getActiveNetworkInfo().isConnected()) {
                return true;
        } else {
            return false;
        }
    }
}

Per maggiori dettagli visita Come controllare lo stato della connettività di rete / Internet Android


5

Il miglior approccio:

public static boolean isOnline() {
    try {
    InetAddress.getByName("google.com").isReachable(3);

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

1
Mi piace questo approccio ma devo sottolineare alcune cose. isReachable () restituisce un valore booleano, quindi invece di restituire true nella sezione try, è possibile farlo come booleano connesso = InetAddress.getByName ("google.com"). isReachable (3); quindi tornare connesso. Inoltre, isReacheable genera eccezioni IOException ed IllegalArgumentException, quindi sarà una buona idea sostituire il UnknownHostException con IllegalArgumentException e includere un terzo catch: catch (Exception E).
Yash,

2
Ma poi, isReachable utilizza ICMP che potrebbe richiedere i privilegi di root e utilizza la porta 7 che di solito non ha servizi in esecuzione sugli ultimi sistemi. Pertanto, il modo migliore per controllare il percorso verso un servizio online è tramite il normale TCP; quindi un voto negativo.
Yash,

5

Di seguito è riportato il codice della mia Utilsclasse:

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

5
public class Network {

Context context;

public Network(Context context){
    this.context = context;
}

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

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

}

Come tutti gli altri che non hanno letto il problema, questo non risolve il problema, dal momento che non controlla realmente la connessione a Internet. Una connessione a un hotspot wifi locale tornerà vera, anche se l'hotspot non ti consentirà di accedere a Internet.
Pedro Pombeiro,

5

Puoi utilizzare questo metodo per rilevare la disponibilità della rete

public static boolean isDeviceOnline(Context context) {
        boolean isConnectionAvail = false;
        try {
            ConnectivityManager cm = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo netInfo = cm.getActiveNetworkInfo();
            return netInfo.isConnected();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isConnectionAvail;
    }

5

Ho applicato la soluzione fornita da @Levit e creato una funzione che non chiamerà la richiesta HTTP aggiuntiva.

Risolverà l'errore Unable to Resolve Host

public static boolean isInternetAvailable(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (activeNetwork == null) return false;

    switch (activeNetwork.getType()) {
        case ConnectivityManager.TYPE_WIFI:
            if ((activeNetwork.getState() == NetworkInfo.State.CONNECTED ||
                    activeNetwork.getState() == NetworkInfo.State.CONNECTING) &&
                    isInternet())
                return true;
            break;
        case ConnectivityManager.TYPE_MOBILE:
            if ((activeNetwork.getState() == NetworkInfo.State.CONNECTED ||
                    activeNetwork.getState() == NetworkInfo.State.CONNECTING) &&
                    isInternet())
                return true;
            break;
        default:
            return false;
    }
    return false;
}

private static boolean isInternet() {

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

    return false;
}

Ora chiamalo come,

if (!isInternetAvailable(getActivity())) {
     //Show message
} else {
     //Perfoem the api request
}

4

1
Ma il metodo descritto non controlla realmente la connessione a Internet, ma controlla solo se è stata stabilita una connessione (se ha accesso a Internet o meno). Il titolo di quel documento ufficiale è davvero fuorviante.
Tiago,

2
Dare una risposta alla domanda è meglio che pubblicare un link alle informazioni. Cosa succede se il collegamento si interrompe? Non avremo risposta.
Jose Llausas,

4

Ho esaminato tutte le risposte e ho trovato la mia risposta, che controlla innanzitutto se Internet è disponibile e se Internet è disponibile, quindi controlla se è attivo o meno.

Ho incluso tutti i metodi e le classi necessari per verificare la connessione a Internet attiva.

NetworkUtils.class

public class NetworkUtils {

    public static final int STATUS_CONNECTED = 0 ;

    public static boolean isInternetAvailable(Context ctx){
        ConnectivityManager cm = (ConnectivityManager)ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    }

    public static int isInternetActiveWithPing() {
        try {
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
            int exitValue = process.waitFor();
            return exitValue;
        } catch (Exception ex) {
            return -1;
        }
    }

    public static boolean isInternetActiveWithInetAddress() {
        try {
            InetAddress inetAddress = InetAddress.getByName("www.google.com");
            return inetAddress != null && !inetAddress.toString().equals("");
        } catch (Exception ex) {
            return false;
        }
    }

    public static void displayInternetConnectionMessage(Context ctx){
        Toast.makeText(ctx, "Check Internet Connection", Toast.LENGTH_SHORT).show();
    }
}

Puoi verificare se Internet è attivo usando il codice seguente:

 private void checkInternetConnection() {
        if (NetworkUtils.isInternetAvailable(this)) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (NetworkUtils.isInternetActiveWithPing() == NetworkUtils.STATUS_CONNECTED) {
                        performNetworkingOperations();
                    } else {
                        if (NetworkUtils.isInternetActiveWithInetAddress()) {
                            performNetworkingOperations();
                        } else {
                            displayConnectionMessage();
                        }
                    }
                }
            }).start();

        } else {
            displayConnectionMessage();
        }
    }

    private void performNetworkingOperations() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "Internet is Available", Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void displayConnectionMessage() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                NetworkUtils.displayInternetConnectionMessage(MainActivity.this);
            }
        });
    }

Migliore pacchetto di threading in NetworkUtils e quindi "costringi" lo sviluppatore a non usare in modo improprio il tuo metodo
Ewoks

Per rimuovere un ulteriore se condizione. if ((NetworkUtils.isInternetActiveWithPing () == NetworkUtils.STATUS_CONNECTED) || NetworkUtils.isInternetActiveWithInetAddress ()) {// Do Network Operation} else {// Error Message}
Jawad Zeb

4

Molto importante verificare se abbiamo connettività con isAvailable () e se è possibile stabilire una connessione con isConnected ()

private static ConnectivityManager manager;

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

e puoi eliminare il tipo di rete attiva WiFi :

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

o mobile Móvil :

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

non dimenticare le autorizzazioni:

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

Bel riassunto dei componenti di connettività del dispositivo, basta avvolgerli nelle istruzioni try / catch per evitare arresti anomali. Allo stesso modo, effettua semplicemente le tue chiamate HttpURLConnection di routine, purché siano avvolte nella gestione degli errori, presto saprai se hai una connessione Internet o meno
rangi

4

Kotlin e coroutine

Ho inserito la funzione in a ViewModel, che ha il viewModelScope. Usando un osservabile LiveDatainformo un'attività sulla connessione.

ViewModel

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

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

                    withContext(Dispatchers.Main) {
                        _connection.value = true
                    }
                }
                catch(ex: IOException) {
                    withContext(Main) {
                        _connection.value = false
                    }
                }
            }
        }
    }
 private val _connection = MutableLiveData<Boolean>()
 val connection: LiveData<Boolean> = _connection

Attività

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

3

Basta creare la seguente classe che verifica la connessione a Internet:

public class ConnectionStatus {

    private Context _context;

    public ConnectionStatus(Context context) {
        this._context = context;
    }

    public boolean isConnectionAvailable() {
        ConnectivityManager connectivity = (ConnectivityManager) _context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null)
                for (int i = 0; i < info.length; i++)
                    if (info[i].getState() == NetworkInfo.State.CONNECTED) {
                        return true;
                    }
        }
        return false;
    }
}

Questa classe contiene semplicemente un metodo che restituisce il valore booleano dello stato della connessione. Pertanto, in termini semplici, se il metodo trova una connessione valida a Internet, il valore restituito è true, altrimenti falsese non viene trovata alcuna connessione valida.

Il seguente metodo in MainActivity chiama quindi il risultato dal metodo precedentemente descritto e richiede all'utente di agire di conseguenza:

public void addListenerOnWifiButton() {
        Button btnWifi = (Button)findViewById(R.id.btnWifi);

        iia = new ConnectionStatus(getApplicationContext());

        isConnected = iia.isConnectionAvailable();
        if (!isConnected) {
            btnWifi.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
                    Toast.makeText(getBaseContext(), "Please connect to a hotspot",
                            Toast.LENGTH_SHORT).show();
                }
            });
        }
        else {
            btnWifi.setVisibility(4);
            warning.setText("This app may use your mobile data to update events and get their details.");
        }
    }

Nel codice sopra, se il risultato è falso (quindi non esiste una connessione Internet, l'utente viene portato al pannello Wi-Fi Android, dove viene richiesto di connettersi a un hotspot Wi-Fi.


3

Aggiornamento 29/06/2015 Se si utilizza Xamarin.Android e si desidera verificare la connettività, è possibile utilizzare un pacchetto Nuget che offre questa funzionalità su più piattaforme. I buoni candidati sono qui e qui . [Fine dell'aggiornamento]

Le risposte sopra sono abbastanza buone, ma sono tutte in Java e quasi tutte verificano la connettività. Nel mio caso, avevo bisogno di connettività con un tipo specifico di connessione e sto sviluppando su Xamarin.Android. Inoltre, non passo un riferimento alle mie attività Contesto nel livello Hardware, utilizzo il Contesto dell'applicazione. Quindi ecco la mia soluzione, nel caso qualcuno venga qui con requisiti simili. Tuttavia, non ho eseguito test completi, aggiornerò la risposta una volta terminato il test

using Android.App;
using Android.Content;
using Android.Net;

namespace Leopard.Mobile.Hal.Android
{
    public class AndroidNetworkHelper
    {
        public static AndroidNetworkStatus GetWifiConnectivityStatus()
        {
            return GetConnectivityStatus(ConnectivityType.Wifi);
        }

        public static AndroidNetworkStatus GetMobileConnectivityStatus()
        {
            return GetConnectivityStatus(ConnectivityType.Mobile);
        }

        #region Implementation

        private static AndroidNetworkStatus GetConnectivityStatus(ConnectivityType connectivityType)
        {
            var connectivityManager = (ConnectivityManager)Application.Context.GetSystemService(Context.ConnectivityService);
            var wifiNetworkInfo = connectivityManager.GetNetworkInfo(connectivityType);
            var result = GetNetworkStatus(wifiNetworkInfo);
            return result;
        }

        private static AndroidNetworkStatus GetNetworkStatus(NetworkInfo wifiNetworkInfo)
        {
            var result = AndroidNetworkStatus.Unknown;
            if (wifiNetworkInfo != null)
            {
                if (wifiNetworkInfo.IsAvailable && wifiNetworkInfo.IsConnected)
                {
                    result = AndroidNetworkStatus.Connected;
                }
                else
                {
                    result = AndroidNetworkStatus.Disconnected;
                }
            }
            return result;
        } 

        #endregion
    }

    public enum AndroidNetworkStatus
    {
        Connected,
        Disconnected,
        Unknown
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.