¿Cómo verificar el acceso a internet en Android? InetAddress nunca caduca

658

Tengo un AsyncTaskdispositivo que se supone que verifica el acceso de red a un nombre de host. Pero doInBackground()nunca se agota el tiempo de espera. Alguien tiene una pista?

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();
    }   
}
Vidar Vestnes
fuente
55
Para verificar una conexión a Internet, probablemente la forma más confiable sería hacer ping a uno de los principales servidores de nombres, esto podría hacerse, por ejemplo, con if(Runtime.getRuntime().exec("/system/bin/ping -c 1 8.8.8.8").waitFor()==0) .... Vea mi respuesta para una mejor implementación de esto. Por cierto, la respuesta aceptada (y muchas otras aquí) simplemente verifique si hay una conexión de red , no internet.
Levite
44
No use el método ping, use una comprobación HTTP en su lugar. ICMP está bloqueado en algunas redes, por lo que el ping no funcionará. Por ejemplo: funciona perfectamente en el wifi de mi casa, pero no cuando uso datos móviles en la red de Vodafone (en Hungría). O combine los 2 métodos como alternativa, pero tenga cuidado porque waitFor () esperará unos 20 segundos incluso si se usa -w o -W.
Tamás Bolvári
@ TamásBolvári: Aún mejor sería abordarlo en la capa de TCP. Lo que debería acercarte a la velocidad de un ICMP, con la fiabilidad de una solicitud HTTP. Edité la "respuesta de ping" en consecuencia.
Levite

Respuestas:

556

Conexión de red / acceso a Internet

  • isConnectedOrConnecting()(utilizado en la mayoría de las respuestas) verifica cualquier conexión de red
  • Para saber si alguna de esas redes tiene acceso a Internet , use uno de los siguientes

A) Hacer ping a un servidor (fácil)

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

+ podría ejecutarse en el hilo principal

- no funciona en algunos dispositivos antiguos (Galays S3, etc.), bloquea un tiempo si no hay Internet disponible.

B) Conéctese a un enchufe en Internet (avanzado)

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

+muy rápido (de cualquier manera), funciona en todos los dispositivos, muy confiable

- no se puede ejecutar en el hilo de la interfaz de usuario

Esto funciona de manera muy confiable, en todos los dispositivos, y es muy rápido. Sin embargo, debe ejecutarse en una tarea separada (por ejemplo, ScheduledExecutorServiceo AsyncTask).

Posibles preguntas

  • ¿Es realmente lo suficientemente rápido?

    Sí, muy rápido ;-)

  • ¿No hay una forma confiable de verificar Internet, aparte de probar algo en Internet?

    No hasta donde yo sé, pero hágamelo saber y editaré mi respuesta.

  • ¿Qué pasa si el DNS está caído?

    Google DNS (por ejemplo 8.8.8.8) es el DNS público más grande del mundo. A partir de 2013 atendió 130 mil millones de solicitudes por día. Digamos que su aplicación probablemente no sea la conversación del día.

  • ¿Qué permisos se requieren?

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

    Solo acceso a Internet: sorpresa ^^ (Por cierto, ¿alguna vez has pensado en cómo algunos de los métodos sugeridos aquí podrían tener un pegamento remoto sobre el acceso a Internet, sin este permiso?)

 

Extra: AsyncTaskejemplo de un disparo

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: RxJava/RxAndroidEjemplo de un disparo (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 */}
Levita
fuente
22
¡Esta es una gran paz de código! ¡Lo encontré muy útil en dispositivos que usan tarjetas prepagas! Cuando se quedan sin dinero, tienen acceso a internet disponible, pero no tienen internet. Por lo tanto, solo verificar la conectividad no funcionaría. ¡GRACIAS!
Blejzer
10
Tenga en cuenta que este enfoque es de bloqueo, por lo que no debe ejecutarlo en la interfaz de usuario therad
Sergii
36
@Levit Esta debería ser la respuesta aceptada. La respuesta anterior solo marca Red n NO CONEXIÓN A INTERNET . Y sí, esto es muy rápido. Gracias. De ahí el voto.
Roon13
99
Esta solución no funciona para todos los dispositivos. Algunos dispositivos siempre devuelven 2 como dijo @Salmaan. Los dispositivos que probé tenían conexión a Internet y el objetivo de ping es el servidor DNS de Google, que responde a las solicitudes de ping. Creo que algunos proveedores no permiten solicitudes de ping. Por ejemplo, probé con una tableta Samsung 10.1 (4.3), y la solución no funciona. Cuando ejecuto el comando ping a través de la utilidad de línea de comando, aparece un error de permiso. El comando tampoco funciona en emuladores. Tenga cuidado al usar esta solución.
Eren Yilmaz
99
Este enfoque no funciona en todos los teléfonos. Falla, por ejemplo, en Samsung Galaxy S3. Ver aquí: ¿Por qué el ping funciona en algunos dispositivos y no en otros?
Adil Hussain
1032

Si el dispositivo está en modo avión (o presumiblemente en otras situaciones en las que no hay una red disponible), cm.getActiveNetworkInfo()lo estará null, por lo que debe agregar un nullcheque.

Modificado ( solución de Eddie ) a continuación:

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

Agregue también el siguiente permiso a AndroidManifest.xml:

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

Otro pequeño punto, si absolutamente necesita una conexión de red en el punto dado en el tiempo, entonces podría ser mejor usar en netInfo.isConnected()lugar de netInfo.isConnectedOrConnecting. Sin embargo, supongo que esto depende del caso de uso individual.

gar
fuente
109
En mi opinión, aún debe y debe verificar las excepciones de tiempo de espera de http, ya que puede haber situaciones en las que una red está conectada, pero no habría una conexión a Internet real porque la única forma de acceder es a través de, por ejemplo, VPN, de esta manera usted tiene, para ejemplo, conexión WI-FI pero sin tráfico real de internet. Otra situación es un servidor colgado. Estos son 2 problemas que he ejecutado recientemente y el administrador de conexiones no va a ayudar allí.
medianoche
21
Estoy de acuerdo con medianoche y Pintu, esta respuesta no debería ser la respuesta aceptada, no tiene nada que ver con verificar si estás en Internet. Por ejemplo, si el teléfono está conectado a una red WiFi con un portal cautivo, como en un hotel, esta función volverá a ser verdadera incorrectamente. La respuesta correcta es hacer ping a un servidor en Internet público.
miguel
99
cuando no hay Internet funcionando para mi enrutador, si me conecto al enrutador a través de wifi, el código anterior vuelve a ser verdadero Pero, se supone que no es así, ¿verdad? ¿Me pueden ayudar
MoHaN K RaJ
55
Tuve que agregar el contexto, context.getSystemServiceo no funciona. Tengo mi pista aquí androidhive.info/2012/07/…
Francisco Corrales Morales
1
Buena manera de verificar la disponibilidad de la red. Pero, ¿cómo verificar el acceso a internet?
Tamás Bolvári
296

No es necesario ser complejo. La manera más simple y marco es usar el ACCESS_NETWORK_STATEpermiso y simplemente hacer un método conectado

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

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

También puede usarlo requestRouteToHostsi tiene en mente un host particular y un tipo de conexión (wifi / móvil).

También necesitarás:

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

en tu manifiesto de Android.

Eddie
fuente
82
es mejor hacer una comprobación nula a nivel cm.getActiveNetworkInfo () arrojó un valor nulo si no había una red activa disponible.
Samuel
ver stackoverflow.com/a/11691676/1979773 para una explicación más profunda sobre requestRouteToHost ()
Spartako
Tuve que agregar el contexto, context.getSystemServiceo no funciona. Tengo mi pista aquí androidhive.info/2012/07/…
Francisco Corrales Morales
99
Esta solución se volverá verdadera si está conectado a un punto de acceso WiFi, incluso si este punto de acceso NO tiene conexión a Internet.
Josh
63

Para comenzar getActiveNetworkInfo()a trabajar necesita agregar lo siguiente al manifiesto.

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
azelez
fuente
Esta debería estar definitivamente bajo la respuesta correcta (perder demasiado tiempo averiguando qué demonios está mal).
Indrek Kõue
2
El permiso de INTERNET NO es necesario para esto, solo ACCESS_NETWORK_STATE. INTERNET solo es necesario si realmente está haciendo conexiones a ubicaciones remotas, sin consultar el estado de la radio del dispositivo.
Tom
3
Su respuesta actualmente no es realmente una respuesta, es solo una adición relativamente menor a otras respuestas. Si todas las otras respuestas no estuvieran aquí, ¿tendría sentido su respuesta? Realmente no. Porque si eso es mejor expandir su respuesta con un código sobre cómo usarla, o eliminar su respuesta y agregar la información en otra respuesta (no perderá ninguna reputación)
Tim
Tenga cuidado getActiveNetworkInfo()está en desuso en el nivel API 29.
Desbordamiento de pila
46

Eche un vistazo a la clase ConnectivityManager. Puede usar esta clase para obtener información sobre las conexiones activas en un host. http://developer.android.com/reference/android/net/ConnectivityManager.html

EDITAR: Puedes usar

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

o

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

y analice la enumeración detallada de estado del objeto NetworkInfo devuelto

EDITAR EDITAR: para averiguar si puede acceder a un host, puede usar

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

Obviamente, estoy usando Context.getSystemService (Context.CONNECTIVITY_SERVICE) como proxy para decir

ConnectivityManager cm = Context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.yourMethodCallHere();
Chinmay Kanchi
fuente
No estoy seguro, pero esto parece un código para probar en qué tipo de conexión de red estoy actualmente. Por ejemplo, im en WiFi, no hay ninguna garantía de que router WiFi está conectado con Internett ... para comprobar que en realidad se necesita hacer una solicitud a un InternetServer ...
Vidar Vestnes
1
Hubo un error en la sección EDITAR EDITAR, había dejado de lado la llamada requestRouteToHost (). Vuelva a leer la respuesta ahora :)
Chinmay Kanchi
requestRouteToHost ha quedado en desuso.
Jahaziel
46

mira este código ... funcionó para mí :)

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

Luego, defino el controlador:

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

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

        } else { // code if connected

        }   
    }
};

... y lanza la prueba:

isNetworkAvailable(h,2000); // get the answser within 2000 ms
Gilbou
fuente
3
¿Qué es Google está abajo? Eso también requiere el permiso de INTERNET, que es innecesario para la tarea dada. Finalmente, eso consume datos (incluso si es insignificante). Esto simplemente parece un gran error.
Tom
28
@ Para ser justos, esta es probablemente la única respuesta correcta. Los otros ejemplos simplemente muestran si hay una conexión de red disponible y / o si hay una conexión a esa red, pero no responda la pregunta si esa red también puede hacer una conexión remota (por ejemplo, a un sitio web). Así que esto responde a la Q posters, y las otras respuestas no lo hacen
slinden77
2
@dmmh Sí, desafortunadamente es cierto por lo que he visto con las API de Android. Quizás un simple ping podría ser mejor, stackoverflow.com/questions/3905358/… . Si estaba realmente preocupado, incluso podría incluir una lista de IP para hacer ping, porque si bien existe una pequeña posibilidad de que Google alguna vez se caiga, hay una posibilidad aún menor de que Google, Bing y Yahoo estén caídos el mismo día . Solo mis pensamientos.
Tom
10
No tiene sentido hacer esta verificación. Si va a gastar el tiempo del sistema y los recursos de la red para conectarse a Google, podría haberlos gastado conectándose al recurso que realmente le interesa.
Benjamin
16
¡En China Google fue bloqueado!
Anthone
26

Encontrado en y modificado (!) Desde este enlace :

En su archivo de manifiesto agregue al menos:

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

Probablemente ya tenga el permiso de INTERNET si está accediendo a él. Entonces, una función booleana que permite probar la conectividad es:

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;
    }
}
Ajhar
fuente
18

Hice este código, es el más simple y es solo un booleano. preguntandoif(isOnline()){

Obtiene si hay una conexión y si puede conectarse a una página el código de estado 200(conexión estable).

Asegúrese de agregar el correcto INTERNETy los ACCESS_NETWORK_STATEpermisos.

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;
}
Android.Thirio.nl
fuente
66
Tal vez debería reemplazar 200 por HttpURLConnection.HTTP_OK
Yash
55
¿Qué pasa si Google está caído?
Yauraw Gadav
12

A mí me funciona:

Para verificar la disponibilidad de la red:

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

Para verificar el acceso 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;
}
Musculaa
fuente
Esta es una gran solución para verificar si un servidor funciona bien, funciona realmente bien. ¡Gracias!
Williew
1
isOnline () no debería ejecutarse en el hilo principal en absoluto, como si hubiera señal de wi-fi pero no internet, tomará demasiado tiempo y bloqueará el hilo principal.
Humazed
9

Hay más de una manera

Primero, el camino más corto pero ineficiente

Solo se necesita permiso de estado de red

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

Entonces este método,

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

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

        return isConnected;

    }

Como se ve en las respuestas, ConnectivityManageres una solución, solo la agregué dentro de un método, este es un método simplificado, todo uso
ConnectivityManagerdevuelve verdadero si hay un acceso a la red, no acceso a Internet, significa que su WiFi está conectado a un enrutador pero el enrutador no tiene Internet devuelve verdadero, verifica la disponibilidad de conexión

Segundo, de manera eficiente

Estado de red y permisos de Internet necesarios

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

Entonces esta clase,

 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
            }

        }


    }

Llamada CheckInternetAsyncTask

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

Algunas explicaciones: -

  • tienes que revisar Internet AsyncTask, de lo contrario puede arrojar android.os.NetworkOnMainThreadExceptionen algunos casos

  • ConnectivityManager se utiliza para verificar el acceso a la red si la solicitud de envío verdadero (Ping)

  • Solicitud de envío a http://clients3.google.com/generate_204, Se sabe que esta conocida URL devuelve una página vacía con un estado HTTP 204, esto es más rápido y más eficiente que http://www.google.com, lea esto . si tiene un sitio web, es preferible poner su sitio web en lugar de google, solo si lo usa dentro de la aplicación

  • Se puede cambiar el intervalo de tiempo de espera (20 ms -> 2000 ms), se suele utilizar 1500 ms

Mohamed Embaby
fuente
2
Buena pregunta, es triste que no tengas más puntos. Esta debe ser la respuesta correcta.
Jhon Fredy Trujillo Ortega
Soy nuevo en android. sin embargo, esta respuesta está bien cubierta y recibe más atención @ 7569106
Mazen Embaby
1
La mejor y completa respuesta, gracias. si alguien tiene un aviso en el sitio web, a esa condición le debe gustar esto urlc.getResponseCode () == 200 y no necesita verificar urlc.getContentLength () == 0
AREF
su segunda opción se
cuelga,
se congela la aplicación
nafees ahmed
8

De todo lo que he visto hasta ahora, la forma más corta y limpia debería ser:

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

PD: Esto no hace ping a ningún host, solo verifica el estado de la conexión, por lo que si su enrutador no tiene conexión a Internet y su dispositivo está conectado a él, este método volverá verdadero aunque no tenga Internet.
Para una prueba real, recomendaría ejecutar una solicitud HttpHead (por ejemplo, en www.google.com) y verificar el estado, si es 200 OK, todo está bien y su dispositivo tiene una conexión a Internet.

Nickolaus
fuente
Quería poner este método en una clase global, así que tuve que usar esta versión para poder pasar el Contexto de la Actividad desde la que lo llamaba. ¡Gracias!
RyanG
8

Aquí está el método que uso:

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

Aún mejor, verifique que esté "conectado":

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

Aquí está cómo usar el método:

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

Permiso necesario:

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

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

Jared Burrows
fuente
7

Un caso de uso importante en dispositivos móviles para garantizar que exista una conexión real. Este es un problema común cuando un usuario móvil ingresa a una red Wifi con un "Portal cautivo", en el que necesita iniciar sesión. Utilizo esta función de bloqueo en segundo plano para asegurar que exista una conexión.

/*
 * 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;
}
usuario1528493
fuente
3
+1 para verificar realmente la conectividad de extremo a extremo. Sin embargo, para la situación del "Portal cautivo", he descubierto que muchos pasarán la prueba anterior incluso si no ha iniciado sesión: obtiene la página de inicio de sesión y una respuesta 200 sin importar qué url solicite. Así que intento acceder a una página en mi propio dominio que sé que no existe, y me aseguro de obtener un 404. Alternativamente, puede acceder a una página existente conocida, asegurarse de obtener un 200 y verificar el contenido que se devuelve para asegurarse de que sea lo que espera.
GreyBeardedGeek 01 de
6

Puede iterar sobre todas las conexiones de red y verificar si hay al menos una conexión disponible:

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;
}
Emre Yazici
fuente
6

Para mí no era una buena práctica verificar el estado de la conexión en la clase Actividad, porque

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

debe llamarse allí, o debe empujar hacia abajo su instancia de Actividad (contexto) a la clase de controlador de conexión para poder verificar el estado de la conexión allí Cuando no hay conexión disponible (wifi, red), cojo la excepción 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();
}

De esta forma puedo manejar este caso junto con los otros casos en la misma clase (mi servidor siempre responde con una cadena json)

Hola
fuente
6

A mí me funciona. Pruébalo.

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());
}}
selva_pollachi
fuente
Esta respuesta no puede funcionar ahora, ya que no podemos acceder a la red en el hilo principal ahora.
正宗 白 布鞋
1
Quiero decir, desde el nivel de API 11, esto no funciona. Motivo: developer.android.com/reference/android/os/… . Si funciona para usted, significa que está ejecutando este código en un dispositivo Android antiguo. (antes de GB).
正宗 白 布鞋
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder () .permitAll (). Build (); StrictMode.setThreadPolicy (política); agregue estas dos líneas a su programa para evitar la excepción del hilo principal de la red
selva_pollachi
Ok, no debería decir que esto no puede funcionar, debería decir que puede funcionar (por versión anterior de destino o configuración de Strictmode), pero se desaconseja. Esto puede causar ANR fácilmente. (Con una configuración de tiempo de espera tan alta en httpurlconnection)
正宗 白 布鞋
ya..tienes razón .. solo pongo esto porque esta también es una de las formas.
selva_pollachi
6

Este método le brinda la opción de un método realmente rápido (para comentarios en tiempo real) o un método más lento (para verificaciones únicas que requieren confiabilidad)

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;
}
WonderWorker
fuente
5

Estoy usando este código en lugar de 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();
    }
Vidar Vestnes
fuente
Sería genial si hubiera aclarado si la IOException significa que no hay conexión a Internet y qué tan confiable podría ser.
Milad.Nozari
5

No es complejo verificar el estado de la red Android / conectividad a Internet. La siguiente DetectConnectionclase lo ayudará a verificar este estado:

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

Para obtener más detalles, visite Cómo verificar el estado de conectividad de red / Internet de Android

JSoporte
fuente
5

Mejor enfoque:

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

    return true;
    } catch (UnknownHostException e){
    return false;
    } catch (IOException e){
    return false;
    }
    }
Lo juego
fuente
1
Me gusta este enfoque, pero tengo que señalar algunas cosas. isReachable () devuelve un valor booleano, por lo tanto, en lugar de devolver verdadero en la sección de prueba, puede hacerlo como boolean conectado = InetAddress.getByName ("google.com"). isReachable (3); luego vuelve conectado. Además, isReacheable lanza excepciones IOException e IllegalArgumentException, por lo tanto, será una buena idea reemplazar UnknownHostException con IllegalArgumentException e incluir un tercer catch: catch (Excepción E).
Yash
2
Pero entonces, isReachable usa ICMP que puede requerir privilegios de root y usa el puerto 7 que generalmente no tiene servicios en ejecución en los últimos sistemas. Por lo tanto, la mejor manera de verificar la ruta a un servicio en línea es mediante TCP regular; de ahí un voto negativo.
Yash
5

El siguiente es el código de mi Utilsclase:

public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager connectivityManager 
              = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
Mahendra Liya
fuente
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();
}

}
usuario2912903
fuente
Como todos los demás que no leyeron el problema, esto no resuelve el problema, ya que realmente no comprueba la conexión a Internet. Una conexión a un punto de acceso wifi local volverá a ser verdadera, incluso si el punto de acceso no le permite acceder a Internet.
Pedro Pombeiro
5

Puede usar este método para detectar la disponibilidad de la red.

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;
    }
Akshay Paliwal
fuente
5

He aplicado la solución proporcionada por @Levit y he creado una función que no llamará a la solicitud Http adicional.

Resolverá el error 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;
}

Ahora llámalo como,

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

Esto está cubierto en los documentos de Android http://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html

kreker
fuente
1
Pero el método descrito allí realmente no verifica la conexión a Internet, solo verifica si se establece una conexión (si tiene acceso a Internet o no). El título de ese documento oficial es realmente engañoso.
Tiago
2
Dar una respuesta a la pregunta es mejor que simplemente publicar un enlace a la información. ¿Qué pasa si el enlace se corta? No tendremos respuesta.
Jose Llausas
4

Revisé todas las respuestas y llegué a mi propia respuesta, que primero verifica si Internet está disponible y si Internet está disponible, luego verifica si está activo o no.

He incluido todos los métodos y clases necesarios para verificar la conexión activa a Internet.

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

Puede verificar si Internet está activo usando el siguiente código:

 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);
            }
        });
    }
Rajesh
fuente
Mejore el enhebrado de paquetes en sus NetworkUtils y, por lo tanto, "obligue" al desarrollador a no usar su método de manera incorrecta
Ewoks
Para quitar un extra si condición. if ((NetworkUtils.isInternetActiveWithPing () == NetworkUtils.STATUS_CONNECTED) || NetworkUtils.isInternetActiveWithInetAddress ()) {// Hacer operación de red} else {// Mensaje de error}
Jawad Zeb
4

Es muy importante verificar si tenemos conectividad con isAvailable () y si es posible establecer una conexión 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();
}

y puede determinar el tipo de red WiFi activa :

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 móvil 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;
}

no olvides los permisos:

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
   <uses-permission android:name="android.permission.INTERNET" />
Jorgesys
fuente
Buen resumen de los componentes de conectividad del dispositivo, solo necesita envolverlos en declaraciones try / catch para evitar bloqueos. Del mismo modo, solo haga sus llamadas de rutina HttpURLConnection, siempre que estén envueltas en el manejo de errores, pronto sabrá si tiene o no una conexión a Internet
rangi
4

Kotlin y corutinas

He colocado la función en a ViewModel, que tiene el viewModelScope. Usando un observable LiveDatainformo a una actividad sobre la conexión.

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

Actividad

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

Simplemente cree la siguiente clase que verifica la conexión 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;
    }
}

Esta clase simplemente contiene un método que devuelve el valor booleano del estado de la conexión. Por lo tanto, en términos simples, si el método encuentra una conexión válida a Internet, el valor de retorno es true, de lo contrariofalse si no se encuentra una conexión válida.

El siguiente método en MainActivity llama al resultado del método descrito anteriormente, y solicita al usuario que actúe en consecuencia:

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

En el código anterior, si el resultado es falso (por lo tanto, no hay conexión a Internet, el usuario es llevado al panel de wi-fi de Android, donde se le solicita que se conecte a un punto de acceso inalámbrico).

Michele La Ferla
fuente
3

Actualización 29/06/2015 Si está utilizando Xamarin.Android y desea verificar la conectividad, puede usar un paquete Nuget que le brinde esta funcionalidad en múltiples plataformas. Los buenos candidatos están aquí y aquí. . [Fin de la actualización]

Las respuestas anteriores son bastante buenas, pero están todas en Java, y casi todas verifican la conectividad. En mi caso, necesitaba tener conectividad con un tipo específico de conexión y estoy desarrollando en Xamarin.Android. Además, no paso una referencia al Contexto de mis actividades en la capa Hardware, uso el Contexto de la aplicación. Así que aquí está mi solución, en caso de que alguien venga con requisitos similares. Sin embargo, no he realizado pruebas completas, actualizaré la respuesta una vez que haya terminado con mis pruebas

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
    }
Tiene AlTaiar
fuente