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

后端 未结 30 3308
猫巷女王i
猫巷女王i 2020-11-21 04:45

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?

相关标签:
30条回答
  • 2020-11-21 04:50

    Im using this code instead of the 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();
        }
    
    0 讨论(0)
  • 2020-11-21 04:50

    Just create the following class which checks for an internet connection:

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

    This class simply contains a method which returns the boolean value of the connection status. Therefore in simple terms, if the method finds a valid connection to the Internet, the return value is true, otherwise false if no valid connection is found.

    The following method in the MainActivity then calls the result from the method previously described, and prompts the user to act accordingly:

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

    In the above code, if the result is false, (therefore there is no internet connection, the user is taken to the Android wi-fi panel, where he is prompted to connect to a wi-fi hotspot.

    0 讨论(0)
  • 2020-11-21 04:51

    This method gives you the option for a really fast method (for real time feedback) or a slower method (for one off checks that require reliability)

    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;
    }
    
    0 讨论(0)
  • 2020-11-21 04:52

    If the device is in airplane mode (or presumably in other situations where there's no available network), cm.getActiveNetworkInfo() will be null, so you need to add a null check.

    Modified (Eddie's solution) below:

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

    Also add the following permission to the AndroidManifest.xml:

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

    One other small point, if you absolutely need a network connection at the given point in time, then it might be better to use netInfo.isConnected() rather than netInfo.isConnectedOrConnecting. I guess this is up to the individual use-case however.

    0 讨论(0)
  • 2020-11-21 04:53

    Network connection / Internet access

    • isConnectedOrConnecting() (used in most answers) checks for any network connection
    • To know whether any of those networks have internet access, use one of the following

    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

    • Is it really fast enough?

      Yes, very fast ;-)

    • Is there no reliable way to check internet, other than testing something on the internet?

      Not as far as I know, but let me know, and I will edit my answer.

    • What if the DNS is down?

      Google DNS (e.g. 8.8.8.8) is the largest public DNS in the world. As of 2013 it served 130 billion requests a day. Let 's just say, your app would probably not be the talk of the day.

    • Which permissions are required?

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

      Just internet access - surprise ^^ (Btw have you ever thought about, how some of the methods suggested here could even have a remote glue about internet access, without this permission?)

     

    Extra: One-shot AsyncTask Example

    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 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 */}
    
    0 讨论(0)
  • 2020-11-21 04:53

    Here is the method I use:

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

    Even better, check to make sure it is "connected":

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

    Here is how to use the method:

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

    Permission needed:

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

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

    0 讨论(0)
提交回复
热议问题