如何在Android上检查互联网访问?InetAddress 永远不会超时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1560788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:16:08  来源:igfitidea点击:

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

androidnetworkingasynchronous

提问by Vidar Vestnes

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

我得到了一个AsyncTask应该检查对主机名的网络访问。但是doInBackground()永远不会超时。有人有线索吗?

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

采纳答案by Levite

Network connection / Internet access

网络连接/互联网访问

  • isConnectedOrConnecting()(used in most answers) checks for any networkconnection
  • To know whether any of those networks have internetaccess, use one of the following
  • isConnectedOrConnecting()(在大多数答案中使用)检查任何网络连接
  • 要了解这些网络中是否有任何一个可以访问Internet,请使用以下方法之一

A) Ping a Server (easy)

A) Ping 一个服务器(简单)

// 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.

-不适用于某些旧设备(Galays S3 等),如果没有互联网可用,它会阻塞一段时间。

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

B) 连接到 Internet 上的 Socket(高级)

// 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, veryreliable

+非常快(无论哪种方式),适用于所有设备,非常可靠

-can't run on the UI thread

-无法在 UI 线程上运行

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

这在每个设备上都非常可靠,并且速度非常快。它需要在单独的任务中运行(例如ScheduledExecutorServiceAsyncTask)。

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?)

  • 真的够快吗?

    是的,非常快;-)

  • 除了在互联网上测试某些东西之外,没有可靠的方法来检查互联网吗?

    据我所知,但让我知道,我会编辑我的答案。

  • 如果 DNS 关闭怎么办?

    Google DNS(例如8.8.8.8)是世界上最大的公共 DNS。截至 2013 年,它每天处理 1300 亿个请求。我们只是说,您的应用程序可能不会成为今天的话题。

  • 需要哪些权限?

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

    只是互联网访问 - 惊喜^^(顺便说一句,你有没有想过,如果没有这个许可,这里建议的一些方法甚至可以远程连接互联网访问?)

 

 

Extra: One-shot AsyncTaskExample

补充:一次性AsyncTask示例

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/RxAndroidExample (Kotlin)

额外:一次性RxJava/RxAndroid示例(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 */}

回答by gar

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 nullcheck.

如果设备处于飞行模式(或者可能在没有可用网络的其他情况下),cm.getActiveNetworkInfo()则将是null,因此您需要添加一个null检查。

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:

还要向 中添加以下权限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.

另外一个小点,如果你绝对需要在给定时间点的网络连接,那么它可能是更好地使用netInfo.isConnected(),而不是netInfo.isConnectedOrConnecting。但是,我想这取决于个人用例。

回答by Eddie

No need to be complex. The simplest and framework manner is to use ACCESS_NETWORK_STATEpermission and just make a connected method

无需复杂。最简单的框架方式就是使用ACCESS_NETWORK_STATE权限,只做一个连接的方法

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

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

You can also use requestRouteToHostif you have a particualr host and connection type (wifi/mobile) in mind.

requestRouteToHost如果您有特定的主机和连接类型(wifi/移动),您也可以使用。

You will also need:

您还需要:

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

in your android manifest.

在你的安卓清单中。

回答by azelez

To get getActiveNetworkInfo()to work you need to add the following to the manifest.

要开始getActiveNetworkInfo()工作,您需要将以下内容添加到清单中。

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

回答by Chinmay Kanchi

Take a look at the ConnectivityManager class. You can use this class to get information on the active connections on a host. http://developer.android.com/reference/android/net/ConnectivityManager.html

查看 ConnectivityManager 类。您可以使用此类来获取有关主机上活动连接的信息。http://developer.android.com/reference/android/net/ConnectivityManager.html

EDIT: You can use

编辑:您可以使用

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

or

或者

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

and parse the DetailedState enum of the returned NetworkInfo object

并解析返回的 NetworkInfo 对象的详细状态枚举

EDIT EDIT: To find out whether you can access a host, you can use

编辑 编辑:要了解您是否可以访问主机,您可以使用

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

Obviously, I'm using Context.getSystemService(Context.CONNECTIVITY_SERVICE) as a proxy to say

显然,我使用 Context.getSystemService(Context.CONNECTIVITY_SERVICE) 作为代理说

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

回答by Gilbou

check this code... it worked for me :)

检查此代码...它对我有用:)

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

Then, I define the handler:

然后,我定义处理程序:

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

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

        } else { // code if connected

        }   
    }
};

...and launch the test:

...并启动测试:

isNetworkAvailable(h,2000); // get the answser within 2000 ms

回答by Ajhar

Found at and modified (!) from this link:

在此链接中找到并修改(!):

In your manifest file add at least:

在您的清单文件中至少添加:

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

You probably already have the INTERNET permission if you are accessing it. Then a boolean function that allows to test for connectivity is:

如果您正在访问它,您可能已经拥有 INTERNET 权限。然后允许测试连通性的布尔函数是:

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

回答by Android.Thirio.nl

I made this code, it is the simplest and it is just a boolean. by asking if(isOnline()){

我做了这个代码,它是最简单的,它只是一个布尔值。通过询问if(isOnline()){

You get if there is a connection and if it can connect to a page the status code 200(stable connection).

如果有连接,如果它可以连接到页面,您将获得状态代码200(稳定连接)。

Make sure to add the correct INTERNETand ACCESS_NETWORK_STATEpermissions.

确保添加正确的INTERNETACCESS_NETWORK_STATE权限。

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

回答by Musculaa

It does works for me:

它对我有用:

To verify network availability:

要验证网络可用性:

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

To verify internet access:

要验证互联网访问:

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

回答by Mohamed Embaby

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 ConnectivityManageris a solution, I just added it within a method this is a simplified method all use
ConnectivityManagerreturns 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

正如在回答看到ConnectivityManager一个解决方案,我只是增加了它的方法中,这是一个简化的方法都用
ConnectivityManager返回true,如果有网络访问不上网,也就是说,如果您的WiFi连接到路由器,但路由器有没有互联网它返回 true,它检查连接可用性

Second, Efficient way

二、高效方式

Network State and Internet Permissions needed

需要网络状态和 Internet 权限

<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

称呼 CheckInternetAsyncTask

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

Some Explanations :-

一些解释:-

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

  • ConnectivityManagerused 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

  • 你必须检查互联网AsyncTask,否则android.os.NetworkOnMainThreadException在某些情况下它会抛出

  • ConnectivityManager用于检查网络访问是否为 true 发送请求(Ping)

  • 请求发送到http://clients3.google.com/generate_204,这个众所周知的 URL 会返回一个带有 HTTP 状态 204 的空页面,这比http://www.google.com阅读这个更快、更有效。如果你有网站,最好把你的网站放在你的网站上而不是谷歌上,只有当你在应用程序中使用它时

  • 超时可更改范围(20ms -> 2000ms),常用1500ms