Pregunta ¿Cómo verificar el acceso a Internet en Android? InetAddress nunca se agota


Conseguí un AsyncTask se supone que debe verificar el acceso de la red a un nombre de host. Pero el 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();
    }   
}

562
2017-10-13 14:59


origen


Respuestas:


Conexión de red / acceso a Internet

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

A) Ping 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 correr en el hilo principal

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

B) Conectarse a un zócalo 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 de confianza

- no se puede ejecutar en el hilo de UI

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

Posibles preguntas

  • ¿Es realmente lo suficientemente rápido?

    Sí, muy rápido ;-)

  • ¿No hay una manera confiable de verificar internet, aparte de probar algo en internet?

    No sé, pero házmelo saber y editaré mi respuesta.

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

    DNS de Google (p. 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 comidilla del día.

  • ¿Qué permisos son necesarios?

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

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

Extra: One-shot AsyncTask Ejemplo

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

363
2017-12-05 09:20



@ Eddie. Solo una edición menor a tu solución - si el dispositivo está en modo avión (o presumiblemente en otras situaciones donde no hay una red disponible), cm.getActiveNetworkInfo() estarán null, entonces necesitas agregar un null comprobar.

Solución modificada a continuación:

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

También agregue el siguiente permiso al AndroidManifest.xml:

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

Otro punto pequeño, si necesitas absolutamente una conexión de red en el punto dado en el tiempo, entonces podría ser mejor usar netInfo.isConnected() más bien que netInfo.isConnectedOrConnecting. Sin embargo, creo que esto depende del uso individual.


998
2017-10-24 16:28



No es necesario que sea complejo. La forma más simple y de marco es usar ACCESS_NETWORK_STATE permiso 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 puedes usar requestRouteToHost si 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 su manifiesto de Android.


287
2018-01-04 20:01



Llegar getActiveNetworkInfo() para trabajar, necesita agregar lo siguiente al manifiesto.

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

63
2017-09-27 10:05



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

Entonces, 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

47
2018-04-27 11:41



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 analizar la enumeración DetailedState del objeto NetworkInfo devuelto

EDITAR EDITAR: Para saber 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();

44
2017-10-13 15:38



Encontrado en y modificado (!) De este enlazar :

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. Luego, 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;
    }
}

25
2018-01-11 10:29



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

Se obtiene si hay una conexión y si se puede conectar a una página el código de estado 200 (conexión estable).

Asegúrese de agregar el correcto INTERNET y ACCESS_NETWORK_STATE permisos

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

15
2017-07-19 13:27



Funciona para mí:

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

11
2018-03-07 16:57



De todo lo que he visto hasta ahora el camino más corto y limpio 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 comprueba el estado de conexión, por lo que si su enrutador no tiene conexión a Internet y su dispositivo está conectado, este método podría regresar cierto aunque no tienes internet.
Para una prueba real, recomendaría excluir una solicitud de HttpHead (por ejemplo, a www.google.com) y verifica el estado, si es 200 OK todo está bien y tu dispositivo tiene una conexión a Internet.


8
2017-09-19 08:10



Un caso de uso importante en los 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 cual necesita iniciar sesión. Uso 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;
}

7
2018-06-13 16:36