javaandroidandroid-asynctaskandroid-networking

How to check internet access on Android? InetAddress never times out


I got a AsyncTask that is supposed to check the network access to a host name. But the doInBackground() is never timed out. Anyone have a clue?

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

Solution

  • Network connection / Internet access

    A) Ping a Server (easy)

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

    + could run on main thread

    - does not work on some old devices (Galays S3, etc.), it blocks a while if no internet is available.

    B) Connect to a Socket on the Internet (advanced)

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

    + very fast (either way), works on all devices, very reliable

    - can't run on the UI thread

    This works very reliably, on every device, and is very fast. It needs to run in a separate task though (e.g. ScheduledExecutorService or AsyncTask).

    Possible Questions

     

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

    fun hasInternetConnection(): Single<Boolean> {
      return Single.fromCallable {
        try {
          // Connect to Google DNS to check for connection
          val timeoutMs = 1500
          val socket = Socket()
          val socketAddress = InetSocketAddress("8.8.8.8", 53)
        
          socket.connect(socketAddress, timeoutMs)
          socket.close()
      
          true
        } catch (e: IOException) {
          false
        }
      }
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
    }
    
    ///////////////////////////////////////////////////////////////////////////////////
    // Usage
    
        hasInternetConnection().subscribe { hasInternet -> /* do something */}
    

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

    public static Single<Boolean> hasInternetConnection() {
        return Single.fromCallable(() -> {
            try {
                // Connect to Google DNS to check for connection
                int timeoutMs = 1500;
                Socket socket = new Socket();
                InetSocketAddress socketAddress = new InetSocketAddress("8.8.8.8", 53);
    
                socket.connect(socketAddress, timeoutMs);
                socket.close();
    
                return true;
            } catch (IOException e) {
                return false;
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }
    
    ///////////////////////////////////////////////////////////////////////////////////
    // Usage
    
        hasInternetConnection().subscribe((hasInternet) -> {
            if(hasInternet) {
    
            }else {
    
            }
        });
    

    Extra: One-shot AsyncTask Example

    Caution: This shows another example of how to do the request. However, since AsyncTask is deprecated, it should be replaced by your App's thread scheduling, Kotlin Coroutines, Rx, ...

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