ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个 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();
    }   
}
要检查 Internet 连接,最可靠的方法可能是 ping 主要名称服务器之一,例如可以使用 if(Runtime.getRuntime().exec("/system/bin/ping -c 1 8.8.8.8").waitFor()==0) ... 来完成。请参阅 my answer 以获得更好的实现。顺便说一句,接受的答案(以及这里的许多其他答案)只是检查网络连接,而不是互联网。
不要使用 ping 方法,而是使用 HTTP 检查。 ICMP 在某些网络上被阻止,因此 ping 不起作用。例如:它在我的家庭 wifi 上完美运行,但当我在 Vodafone 的网络(在匈牙利)上使用移动数据时,它就不行了。或者将这 2 种方法组合为备用方法,但要小心,因为即使使用 -w 或 -W,waitFor() 也会等待大约 20 秒。

B
Bhargav Rao

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

修改 (Eddie's solution) 如下:

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

还将以下权限添加到 AndroidManifest.xml

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

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


imo您仍然应该并且需要检查http超时异常,因为可能会出现网络连接但没有实际互联网连接的情况,因为访问它的唯一方法是通过例如VPN - 你有这种方式例如,有 WI-FI 连接,但没有实际的互联网流量。另一种情况是服务器挂起。这是我最近运行的 2 个问题,连接管理器对此无济于事。
我同意午夜和 Pintu,这个答案不应该是公认的答案,它与检查你是否在互联网上无关。例如,如果手机连接到带有强制门户的 WiFi 网络,例如在酒店,则此函数将错误地返回 true。正确的答案是 ping 公共互联网上的服务器。
当我的路由器没有可用的互联网时,如果我通过 wifi 连接到路由器,那么上面的代码将返回 true。但是,它不应该是,对吧?你能帮助我吗
我必须在 context.getSystemService 中添加上下文,否则它不起作用。我在这里得到了线索androidhive.info/2012/07/…
检查网络可用性的好方法。但是如何检查互联网访问?
A
Aryeetey Solomon Aryeetey

网络连接/互联网访问

isConnectedOrConnecting() (用于大多数答案)检查任何网络连接

要了解这些网络中是否有任何网络可以访问 Internet,请使用以下方法之一

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

+ 可以在主线程上运行

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

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

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

- 无法在 UI 线程上运行

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

可能的问题

真的够快吗?是的,非常快;-)

除了在互联网上测试一些东西之外,没有可靠的方法来检查互联网吗?据我所知,但请告诉我,我将编辑我的答案。

如果 DNS 关闭了怎么办? Google DNS(例如 8.8.8.8)是世界上最大的公共 DNS。截至 2018 年,它每天处理超过一万亿个查询 [1]。我们只是说,您的应用程序可能不会成为今天的热门话题。

需要哪些权限? 只是上网 - 惊喜^^(顺便说一句,你有没有想过,这里建议的一些方法甚至可以远程连接互联网,没有这个权限?)

额外:一次性 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 */}

额外:One-shot RxJava/RxAndroid 示例 (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 {

        }
    });

额外:一次性 AsyncTask 示例

注意: 这显示了如何执行请求的另一个示例。但是,由于 AsyncTask 已被弃用,它应该被您的应用程序的线程调度、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 */ });

这是代码的伟大和平!我发现它在使用预付卡的设备上非常有用!当他们用完钱时,他们可以访问互联网,但没有互联网。因此,仅检查连接是行不通的。谢谢你!
请记住,这种方法是一种阻塞方法,因此您不应该在 UI therad 中执行它
@Levit这应该是公认的答案。上面的答案只是检查 Network n NOT INTERNET CONNECTION。是的,这非常快。谢谢。因此点赞。
此解决方案不适用于所有设备。正如@Salmaan 所说,某些设备总是返回 2。我测试的设备有互联网连接,ping 目标是 Google DNS 服务器——它正在响应 ping 请求。我认为有些供应商不允许 ping 请求。例如,我用三星 10.1 平板电脑(4.3)进行了测试,但该解决方案不起作用。当我通过命令行实用程序运行 ping 命令时,出现权限错误。该命令也不适用于模拟器。小心使用此解决方案。
这种方法不适用于所有手机。例如,它在三星 Galaxy S3 上失败。见这里:Why does ping works on some devices and not others?
J
Jeff Axelrod

不需要很复杂。最简单和框架的方式是使用 ACCESS_NETWORK_STATE 权限,只需创建一个连接的方法

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

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

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

您还需要:

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

在你的 android 清单中。


最好在 cm.getActiveNetworkInfo() 级别进行空值检查,如果没有可用的活动网络,它会抛出空值。
有关 requestRouteToHost() 的更深入解释,请参见 stackoverflow.com/a/11691676/1979773
我必须在 context.getSystemService 中添加上下文,否则它不起作用。我在这里得到了线索androidhive.info/2012/07/…
如果您连接到 WiFi 热点,即使此热点没有互联网连接,此解决方案也会返回 true。
J
Jeff Axelrod

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

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

这个肯定是在正确答案之下(浪费了太多时间来弄清楚到底出了什么问题)。
不需要 INTERNET 权限,只需 ACCESS_NETWORK_STATE。仅当您实际连接到远程位置时才需要 INTERNET,而不是查询设备无线电的状态。
您的答案目前并不是真正的答案,它只是对其他答案的一个相对较小的补充。如果所有其他答案都不在这里,您的答案是否有意义?并不真地。因为如果最好使用有关如何使用它的代码来扩展您的答案,或者删除您的答案并将信息添加到另一个答案中(您不会失去任何声誉)
请注意,getActiveNetworkInfo() 在 API 级别 29 中已弃用。
F
Freewind

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

编辑:您可以使用

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

或者

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

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

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

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

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

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

不确定,但这似乎是测试我当前使用哪种网络连接的代码。例如,我在 WiFi 上,不能保证您的家庭 wifi 路由器已连接到 internett...检查您是否确实需要向 internetserver 发出请求...
EDIT EDIT 部分有一个错误,我遗漏了 requestRouteToHost() 调用。现在重新阅读答案:)
requestRouteToHost 已被弃用。
M
Melquiades

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

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

然后,我定义处理程序:

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

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

        } else { // code if connected

        }   
    }
};

...并启动测试:

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

什么是谷歌失败了?这也需要 INTERNET 权限,这对于给定的任务是不必要的。最后,这会消耗数据(即使微不足道)。这看起来就像一个杂牌。
@Tom 公平地说,这可能是唯一正确的答案。其他示例仅显示网络连接是否可用和/或是否存在与该网络的连接,但不回答该网络是否实际上也可以建立远程连接(例如与网站)的问题。所以这回答了海报Q,而其他答案没有
@dmmh 是的,不幸的是,从我在 Android API 中看到的情况来看,这是真的。也许一个简单的 ping 可能会更好,stackoverflow.com/questions/3905358/…。如果您真的担心,您甚至可以包含要 ping 的 IP 列表,因为虽然 Google 出现故障的可能性很小,但 Google、Bing 和 Yahoo 在同一天出现故障的可能性更小.只是我的想法。
做这个检查没有意义。如果您打算将系统时间和网络资源用于连接到 Google,则可以将它们用于连接到您真正关心的资源。
谷歌在中国被封了!!
V
Vladtn

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

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

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

如果您正在访问它,您可能已经拥有 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;
    }
}

D
Dediqated

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

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

确保添加正确的 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;
}

也许你应该用 HttpURLConnection.HTTP_OK 替换 200
如果谷歌倒闭了怎么办?
M
Musculaa

它对我有用:

要验证网络可用性:

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

要验证互联网访问:

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

这是检查服务器是否正常运行的绝佳解决方案。谢谢!
isOnline() 根本不应该在主线程上运行,就好像有 wi-fi 信号但没有互联网一样,它会花费太长时间并阻塞主线程。
M
Mohamed Embaby

方法不止一种

一、最短但效率低的方法

仅需要网络状态权限

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

那么这个方法,

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

        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        boolean isConnected = activeNetwork != null &&
                activeNetwork.isConnected();

        return isConnected;

    }

正如答案中看到的 ConnectivityManager 是一个解决方案,我只是在一个方法中添加了它,这是一个简化的方法 all use
ConnectivityManager 如果有网络访问而不是 Internet 访问,则返回 true,这意味着如果您的 WiFi 已连接到路由器但路由器没有互联网它返回true,它检查连接可用性

二、高效方式

需要网络状态和 Internet 权限

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

那么这节课,

 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
            }

        }


    }

呼叫CheckInternetAsyncTask

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

一些解释:-

您必须在 AsyncTask 上检查 Internet,否则在某些情况下它可能会抛出 android.os.NetworkOnMainThreadException

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

请求发送到 http://clients3.google.com/generate_204,这个众所周知的 URL 会返回一个带有 HTTP 状态 204 的空页面,这比 http://www.google.com 更快更高效,请阅读这个。如果您有网站,最好将您的网站而不是 google,前提是您在应用程序中使用它

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


很好的问题,很遗憾你没有更多的分数。这一定是正确答案。
我是安卓新手。不过,这是一个很好的答案,它得到了更多的关注@7569106
最好和完整的答案,谢谢。如果有人有一个网站注意到条件必须像这个 urlc.getResponseCode() == 200 并且不需要检查 urlc.getContentLength() == 0
你的第二个选项会崩溃,我不知道为什么
它冻结应用程序
C
Community

这是我使用的方法:

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

更好的是,检查以确保它是“连接的”:

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

以下是该方法的使用方法:

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

需要许可:

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

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


H
Hawklike

Kotlin 和协程

我已将该函数放在具有 viewModelScopeViewModel 中。使用可观察的 LiveData 我通知一个有关连接的活动。

视图模型

 fun checkInternetConnection(timeoutMs: Int) {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                val socket = Socket()
                val socketAddress = InetSocketAddress("8.8.8.8", 53)

                socket.connect(socketAddress, timeoutMs)
                socket.close()

                _connection.postValue(true)
            }
            catch(ex: IOException) {
                _connection.postValue(false)
            }
        }
    }
 private val _connection = MutableLiveData<Boolean>()
 val connection: LiveData<Boolean> = _connection

活动

 private fun checkInternetConnection() {
     viewModel.connection.observe(this) { hasInternet ->
         if(!hasInternet) {
             //hasn't connection
         }
         else {
            //has connection
         }
     }
  }

不工作,不再打电话
@AnshulTyagi 什么不起作用?您是否真的在活动中从视图模型中调用了该方法?如果您想多次检查互联网连接,请在视图模型中添加一个循环(while、repeat 等)并相应地更新 _connection 变量。
N
Nickolaus

到目前为止,我所看到的所有内容中最短和最干净的方式应该是:

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:这不会ping任何主机,它只是检查连接状态,所以如果您的路由器没有互联网连接并且您的设备已连接到它,尽管您没有互联网,但此方法将返回true。对于实际测试,我建议执行 HttpHead 请求(例如到 www.google.com)并检查状态,如果它的 200 OK 一切正常并且您的设备有互联网连接。


我想把这个方法放在一个全局类中,所以我必须使用这个版本,这样我就可以从调用它的 Activity 传递上下文。谢谢!
u
user1528493

移动设备上的一个重要用例是它确保存在实际连接。这是移动用户通过“Captive Portal”进入需要登录的 Wifi 网络时的常见问题。我在后台使用此阻止功能来确保连接存在。

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

+1 用于实际检查端到端连接。然而,对于“强制门户”的情况,我发现即使您没有登录,许多人也会通过上述测试——无论您要求什么 url,您都会得到登录页面和 200 响应。因此,我尝试在我自己的域上访问一个我知道不存在的页面,并确保我得到 404。或者,您可以访问一个已知的现有页面,确保得到 200,然后检查内容返回以确保它是您所期望的。
V
Vidar Vestnes

我使用此代码而不是 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();
    }

如果您能澄清 IOException 是否意味着没有互联网连接以及它的可靠性如何,那就太好了。
它对我有用,但我必须将“http://”转换为“https://”。如果我不转换它将发生错误“不允许明文 HTTP 流量到 www.yourSite.com”。
E
Emre Yazici

您可以遍历所有网络连接并检查是否至少有一个可用连接:

public boolean isConnected() {
    boolean connected = false;

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

    if (cm != null) {
        NetworkInfo[] netInfo = cm.getAllNetworkInfo();

        for (NetworkInfo ni : netInfo) {
            if ((ni.getTypeName().equalsIgnoreCase("WIFI")
                    || ni.getTypeName().equalsIgnoreCase("MOBILE"))
                    && ni.isConnected() && ni.isAvailable()) {
                connected = true;
            }

        }
    }

    return connected;
}

l
laplasz

对我来说,检查 Activity 类中的连接状态不是一个好习惯,因为

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

应该在那里调用,或者您需要将 Activity 实例(上下文)下推到连接处理程序类,以便能够检查那里的连接状态当没有可用连接(wifi、网络)时,我捕获了 UnknownHostException 异常:

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

通过这种方式,我可以将这种情况与同一类中的其他情况一起处理(我的服务器总是以 json 字符串响应)


L
Lo Juego

最佳方法:

public static boolean isOnline() {
    try {
    InetAddress.getByName("google.com").isReachable(3);

    return true;
    } catch (UnknownHostException e){
    return false;
    } catch (IOException e){
    return false;
    }
    }

我喜欢这种方法,但我必须指出一些事情。 isReachable() 返回一个布尔值,因此您可以像 boolean connected = InetAddress.getByName("google.com").isReachable(3); 而不是在 try 部分返回 true ;然后返回连接。此外,isReachable 会引发 IOException 和 IllegalArgumentException 异常,因此将 UnknownHostException 替换为 IllegalArgumentException 并包含第三个 catch 是一个好主意:catch (Exception E)。
但是,isReachable 使用可能需要 root 权限的 ICMP 并使用端口 7,该端口通常在最新系统上没有正在运行的服务。因此,检查在线服务路由的最佳方式是使用常规 TCP;因此投反对票。
s
selva_pollachi

它对我有用。试试看。

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    try {
        URL url = new URL("http://stackoverflow.com/posts/11642475/edit" );
        //URL url = new URL("http://www.nofoundwebsite.com/" );
        executeReq(url);
        Toast.makeText(getApplicationContext(), "Webpage is available!", Toast.LENGTH_SHORT).show();
    }
    catch(Exception e) {
        Toast.makeText(getApplicationContext(), "oops! webpage is not available!", Toast.LENGTH_SHORT).show();
    }
}

private void executeReq(URL urlObject) throws IOException
{
    HttpURLConnection conn = null;
    conn = (HttpURLConnection) urlObject.openConnection();
    conn.setReadTimeout(30000);//milliseconds
    conn.setConnectTimeout(3500);//milliseconds
    conn.setRequestMethod("GET");
    conn.setDoInput(true);

    // Start connect
    conn.connect();
    InputStream response =conn.getInputStream();
    Log.d("Response:", response.toString());
}}

这个答案现在不能用,因为我们现在不能在主线程上访问网络。
我的意思是从 API 级别 11 开始,这不起作用。原因:developer.android.com/reference/android/os/…。如果它适合您,则意味着您正在旧的 android 设备上运行此代码。 (在 GB 之前)。
StrictMode.ThreadPolicy 策略 = 新 StrictMode.ThreadPolicy.Builder() .permitAll().build(); StrictMode.setThreadPolicy(policy);将这两行添加到您的程序中以避免网络主线程异常
好的,我不应该说这不起作用,我应该说它可以工作(通过目标旧版本或 Strictmode 设置)但不鼓励。这可能很容易导致 ANR。 (在 httpurlconnection 中有这么高的超时配置)
是的..你是对的..我只是把这个放了,因为这也是其中一种方式。
A
Akshay Paliwal

您可以使用此方法检测网络可用性 -

public static boolean isDeviceOnline(Context context) {
        boolean isConnectionAvail = false;
        try {
            ConnectivityManager cm = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo netInfo = cm.getActiveNetworkInfo();
            return netInfo.isConnected();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isConnectionAvail;
    }

W
WonderWorker

此方法为您提供了一种非常快速的方法(用于实时反馈)或一种较慢的方法(用于需要可靠性的一次性检查)的选项

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

C
Chilledrat

检查 Android 网络/互联网连接状态并不复杂。下面的 DetectConnection 类将帮助您检查此状态:

import android.content.Context;
import android.net.ConnectivityManager;

public class DetectConnection {
    public static boolean checkInternetConnection(Context context) {
        ConnectivityManager con_manager = (ConnectivityManager) context
                                .getSystemService(Context.CONNECTIVITY_SERVICE);

        if (con_manager.getActiveNetworkInfo() != null
            && con_manager.getActiveNetworkInfo().isAvailable()
            && con_manager.getActiveNetworkInfo().isConnected()) {
                return true;
        } else {
            return false;
        }
    }
}

有关详细信息,请访问 How to Check Android Network / Internet Connectivity Status


M
Mahendra Liya

以下是我的 Utils 类的代码:

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

k
kleopatra
public class Network {

Context context;

public Network(Context context){
    this.context = context;
}

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

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

}

与所有其他没有阅读问题的人一样,这并不能解决问题,因为它并没有真正检查到互联网的连接。与本地 wifi 热点的连接将返回 true,即使该热点不允许您访问 Internet。
k
kreker

这在 android 文档 http://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html 中有介绍


但是那里描述的方法并没有真正检查互联网连接,它只是检查是否建立了连接(是否可以访问互联网)。该官方文档的标题确实具有误导性。
给出问题的答案比仅仅发布信息链接要好。如果链接死了怎么办?我们将没有答案。
J
Jorgesys

检查我们是否与 isAvailable() 建立连接以及是否可以与 isConnected() 建立连接非常重要

private static ConnectivityManager manager;

public static boolean isOnline(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    return networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected();
}

并且您可以确定网络活动的类型 WiFi

public static boolean isConnectedWifi(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
}

或移动 Móvil

public static boolean isConnectedMobile(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE;
}

不要忘记权限:

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

设备连接组件的很好的总结,只需要将它们包装在 try/catch 语句中以避免崩溃。同样,只需进行例行的 HttpURLConnection 调用,只要它们包含在错误处理中,您很快就会知道您是否有互联网连接
J
Jaymin Panchal

我已经应用了@Levit 提供的解决方案,并创建了不会调用额外 Http 请求的函数。

它将解决错误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;
}

现在这样称呼它,

if (!isInternetAvailable(getActivity())) {
     //Show message
} else {
     //Perfoem the api request
}

H
Has AlTaiar

2015 年 6 月 29 日更新 如果您使用 Xamarin.Android 并想要检查连接,您可以使用 Nuget 包,它可以在多个平台上为您提供此功能。好的候选人是 herehere。 [更新结束]

上面的答案都很好,但是它们都是 Java 的,而且几乎都检查了连接性。就我而言,我需要与特定类型的连接建立连接,并且我正在 Xamarin.Android 上进行开发。此外,我没有在硬件层传递对我的活动上下文的引用,我使用应用程序上下文。所以这是我的解决方案,以防有人带着类似的要求来到这里。我还没有完成完整的测试,一旦我完成了我的测试,我会更新答案

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
    }

m
miguel

使用 ConnectivityManager 的其他答案是错误的,因为拥有网络连接并不意味着您可以访问互联网。例如,用户可能连接到咖啡店的 WiFi 门户,但无法访问互联网。要检查互联网是否可以访问,您必须尝试连接到实际的服务器。通常,当您要执行此操作时,您会想到要连接的特定服务器,因此请继续检查是否可以连接到该服务器。这是检查与服务器的连接性的简单方法。

private boolean isOnTheInternet() {
    try {
        URLConnection urlConnection = new URL("http://yourserver").openConnection();
        urlConnection.setConnectTimeout(400);
        urlConnection.connect();
        return true;
    } catch (Exception e) {
        return false;
    }
}

设置 ConnectTimeout 的原因是,否则它默认为 TCP 超时,可能长达数秒。

另请注意,Android 不会让您在主线程上运行它。


R
Rajesh

我已经浏览了所有答案,并提出了自己的答案,首先检查 Internet 是否可用,如果 Internet 可用,则检查它是否处于活动状态。

我已经包含了所有必要的方法和类来检查活动的 Internet 连接。

NetworkUtils.class

public class NetworkUtils {

    public static final int STATUS_CONNECTED = 0 ;

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

    public static int isInternetActiveWithPing() {
        try {
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
            int exitValue = process.waitFor();
            return exitValue;
        } catch (Exception ex) {
            return -1;
        }
    }

    public static boolean isInternetActiveWithInetAddress() {
        try {
            InetAddress inetAddress = InetAddress.getByName("www.google.com");
            return inetAddress != null && !inetAddress.toString().equals("");
        } catch (Exception ex) {
            return false;
        }
    }

    public static void displayInternetConnectionMessage(Context ctx){
        Toast.makeText(ctx, "Check Internet Connection", Toast.LENGTH_SHORT).show();
    }
}

您可以使用以下代码检查 Internet 是否处于活动状态:

 private void checkInternetConnection() {
        if (NetworkUtils.isInternetAvailable(this)) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (NetworkUtils.isInternetActiveWithPing() == NetworkUtils.STATUS_CONNECTED) {
                        performNetworkingOperations();
                    } else {
                        if (NetworkUtils.isInternetActiveWithInetAddress()) {
                            performNetworkingOperations();
                        } else {
                            displayConnectionMessage();
                        }
                    }
                }
            }).start();

        } else {
            displayConnectionMessage();
        }
    }

    private void performNetworkingOperations() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "Internet is Available", Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void displayConnectionMessage() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                NetworkUtils.displayInternetConnectionMessage(MainActivity.this);
            }
        });
    }

在您的 NetworkUtils 中更好地打包线程,因此“强制”开发人员不要误用您的方法
删除一个额外的 if 条件。 if ((NetworkUtils.isInternetActiveWithPing() == NetworkUtils.STATUS_CONNECTED) || NetworkUtils.isInternetActiveWithInetAddress()) { //做网络操作 } else { //错误信息 }