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

后端 未结 30 3446
猫巷女王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 05:00

    One important use case on mobile devices to it ensure an actual connection exists. This is a common problem when a mobile user enters a Wifi network with a "Captive Portal", in which they need to sign in. I use this blocking function in the background to ensure a connection exists.

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

    Update 29/06/2015 If you are using Xamarin.Android and want to check for connectivity, you can use a Nuget package that would give you this functionality on multiple platforms. Good candidates are here and here. [End of Update]

    The Answers above are quite good, but they are all in Java, and almost all of them check for a connectivity. In my case, I needed to have connectivity with a specific type of connection and I am developing on Xamarin.Android. Moreover, I do not pass a reference to my activities Context in the Hardware layer, I use the Application Context. So here is my solution, in case somebody comes here with similar requirements. I have not done full testing though, will update the answer once I am done with my testing

    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
        }
    
    0 讨论(0)
  • 2020-11-21 05:02

    There's more than one way

    First, shortest but Inefficient way

    Network State Permission only needed

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

    Then this method,

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

    As seen in answers ConnectivityManager is a solution, I just added it within a method this is a simplified method all use
    ConnectivityManager returns true if there is a network access not Internet access, means if your WiFi is connected to a router but the router has no internet it returns true, it check connection availability

    Second, Efficient way

    Network State and Internet Permissions needed

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

    Then this class,

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

    Call CheckInternetAsyncTask

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

    Some Explanations :-

    • you have to check Internet on AsyncTask, otherwise it can throw android.os.NetworkOnMainThreadException in some cases

    • ConnectivityManager used to check the network access if true sends request (Ping)

    • Request send to http://clients3.google.com/generate_204, This well-known URL is known to return an empty page with an HTTP status 204 this is faster and more efficient than http://www.google.com , read this. if you have website it's preferred to put you website instead of google, only if you use it within the app

    • Timeout can be changed range (20ms -> 2000ms), 1500ms is commonly used

    0 讨论(0)
  • 2020-11-21 05:02

    Of everything I have seen so far shortest and cleanest way should be:

    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: This does not ping any host, it just checks the connectionstatus, so if your router has no internet connection and your device is connected to it this method would return true although you have no internet.
    For an actual test I would recommend execuding a HttpHead request (e.g. to www.google.com) and check the status, if its 200 OK everything is fine and your device has an internet connection.

    0 讨论(0)
  • 2020-11-21 05:02

    I have applied the solution provided by @Levit and created function that will not call the extra Http Request.

    It will solve the 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;
    }
    

    Now call it like,

    if (!isInternetAvailable(getActivity())) {
         //Show message
    } else {
         //Perfoem the api request
    }
    
    0 讨论(0)
  • 2020-11-21 05:04

    For me it was not a good practice to check the connection state in the Activity class, because

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

    should be called there, or you need to push down your Activity instance (context) to the connection handler class to able to check the connection state there When no available connection (wifi, network) I catch the UnknownHostException exception:

    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 this way I can handle this case along with the other cases in the same class (my server always response back with a json string)

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