检测Android设备是否有可用的互联网连接

746

可能是重复的问题:
如何在Android上检查网络连接? InetAddress永远不会超时

我需要检测Android设备是否连接到互联网。

NetworkInfo类提供了一个非静态方法isAvailable(),听起来很完美。

问题在于:

NetworkInfo ni = new NetworkInfo();
if (!ni.isAvailable()) {
    // do something
}

抛出此错误:

The constructor NetworkInfo is not visible.

很可能有另一个类返回一个NetworkInfo对象,但我不知道是哪个。

  1. 如何使上面的代码片段正常工作?
  2. 我应该如何在在线文档中找到所需信息?
  3. 你能为这种类型的检测建议更好的方法吗?

6
这可能也会有所帮助:这里 - anargund
2
Android.com 上的文章: 确定和监控连接状态 - Alexander Malakhov
2
这里没有一个答案实际上回答了如何检查是否连接到互联网的问题,只是检查是否连接到网络。请参考此答案,尝试建立一个传出的TCP连接来测试:http://stackoverflow.com/a/35647792/1820510 - Xiv
对于任何在2020年查看此内容的人:https://teamtreehouse.com/community/what-can-getactivenetworkinfo-be-replaced-with-since-it-was-deprecated-in-api-29 - VladimirVip
https://stackoverflow.com/a/54957599/10632772 - Asfar Hussain Siddiqui
6个回答

1491

ConnectivityManagergetActiveNetworkInfo()方法返回一个NetworkInfo实例,该实例表示它可以找到的第一个已连接的网络接口,或者如果没有接口连接,则返回null。检查此方法是否返回null应该足以判断互联网连接是否可用。

private boolean isNetworkAvailable() {
    ConnectivityManager connectivityManager 
          = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager != null ? connectivityManager.getActiveNetworkInfo() : null;
    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

你还需要:

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

在你的Android清单文件中。

编辑:

注意,拥有活动网络接口并不保证特定的网络服务可用。网络问题、服务器停机、信号差、被封锁的门户、内容过滤等都可能阻止你的应用程序连接到服务器。例如,在收到Twitter服务的有效响应之前,你无法确定你的应用程序是否能够访问Twitter。


7
如果有人(不必要地)在发起 HTTP 请求之前尝试调用此函数,那么查看连接超时是值得的! :-) - Vikas
144
为了保险起见,我建议返回此代码:return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting();该代码的意思是判断当前网络是否可用。 - Jeff Axelrod
20
如果您正在创建一个Utils方法,即不从可用Context引用的位置访问该方法,则需要将Context作为参数传递进去。 - Mahendra Liya
40
这并不检查手机是否连接到互联网,只是检查是否进行了网络连接。 - miguel
28
很抱歉,不行。这种方式仅检查网络连接是否建立,但不检查设备是否连接到互联网。要真正了解活动的互联网连接情况,您应该使用HttpURLConnection连接到某个主机,ping一些主机(例如google.com),或尝试使用InetAddress.getByName(hostName)。isReachable(timeOut)。 - Dimon
显示剩余22条评论

260

我如下检查Wi-Fi和移动互联网是否可用...

private boolean haveNetworkConnection() {
    boolean haveConnectedWifi = false;
    boolean haveConnectedMobile = false;

    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo[] netInfo = cm.getAllNetworkInfo();
    for (NetworkInfo ni : netInfo) {
        if (ni.getTypeName().equalsIgnoreCase("WIFI"))
            if (ni.isConnected())
                haveConnectedWifi = true;
        if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
            if (ni.isConnected())
                haveConnectedMobile = true;
    }
    return haveConnectedWifi || haveConnectedMobile;
}

显然,它可以轻松地进行修改以检查特定的连接类型,例如,如果您的应用程序需要 Wi-Fi 的潜在更高速度才能正常工作等。


28
代码很好,我只是希望人们在编写Java程序时能坚持Java编程风格,例如haveConnectedWifi、haveConnectedMobile。我知道这是一个小事情,但一致的代码更易读。 - Stuart Axon
6
良好的实践是将字符串放在左边,并且只有在必要时使用equalsIgnoreCase:如果(“WIFI”。equals(ni.getTypeName()))。 - Stuart Axon
82
@Stuart Axon:噢,好吧,我想这就是事实。自从我在20世纪70年代末开始编程以来,我已经用过的语言比我记得住的还要多,显然我养成了许多坏习惯。总的来说,我的原则是:只要它能工作,那么...嗯,它能工作就行了,这就是我关心的全部。上面的代码片段是完全独立的,任何有合理编程经验的人都可以轻松地理解它,并且(最重要的是)如果有人将其剪切并粘贴到他们自己的代码中,它会为他们工作。对不起,因为我是一个Android/Java初学者。 - Squonk
3
并不是为了获得分数或其他任何东西(或者SO是如何运作的),我发现这段代码很有用,但我想以一种抱怨的方式提供一些半有用的反馈意见。 - Stuart Axon
4
@BoD: getType() 提供了更细粒度的信息(我相信),可能会返回 TYPE_MOBILETYPE_MOBILE_DUNTYPE_MOBILE_HIPRI 等。我不关心可用的“移动”连接类型的具体信息,而 getTypeName() 对所有这些类型都只会返回 'MOBILE'。 - Squonk
显示剩余13条评论

80

步骤1:在您的项目中创建一个名为AppStatus的类(您也可以给它取其他名称)。 然后请将下面的代码粘贴到您的代码中:

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;


public class AppStatus {

    private static AppStatus instance = new AppStatus();
    static Context context;
    ConnectivityManager connectivityManager;
    NetworkInfo wifiInfo, mobileInfo;
    boolean connected = false;

    public static AppStatus getInstance(Context ctx) {
        context = ctx.getApplicationContext();
        return instance;
    }

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

        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        connected = networkInfo != null && networkInfo.isAvailable() &&
                networkInfo.isConnected();
        return connected;


        } catch (Exception e) {
            System.out.println("CheckConnectivity Exception: " + e.getMessage());
            Log.v("connectivity", e.toString());
        }
        return connected;
    }
}

步骤2:现在要检查您的设备是否具有网络连接,请将此代码片段添加到您想要检查的任何位置...

if (AppStatus.getInstance(this).isOnline()) {

    Toast.makeText(this,"You are online!!!!",8000).show();

} else {

    Toast.makeText(this,"You are not online!!!!",8000).show();
    Log.v("Home", "############################You are not online!!!!");    
}

7
你真的需要检查 isAvailable 吗?我认为 isConnected 就足够了。 - Alexander Malakhov
1
如果你在构造函数中传递了上下文,为什么还需要在 isOnline 方法中这样做呢? - Svetoslav Marinov
这会导致我的手机崩溃。这在2014年6月还有效吗? - Francisco Corrales Morales
5
@AlexanderMalakhov 实际上,“isAvailable”应该是第一个检查的。我发现,如果连接接口可用,它将返回“true”。有时候(例如当启用“限制后台数据”设置时),“isConnected”可能会返回“false”,表示接口没有活动连接,但“isAvailable”返回“true”,表示接口可用,您可以建立连接(例如传输前台数据)。 - ADTC
5
我做了一个简单的测试。我从我的路由器拔出输入以太网电缆,然后调用了这个方法。因此,设备已连接到Wi-Fi,但Wi-Fi本身未连接到互联网。猜猜看!即使在这种情况下,它仍然返回true。因此,如果我想确保设备已连接到互联网,我应该ping一个众所周知的网站,而不是检查这个方法的返回值。 - shshnk
我猜如果设备连接到移动数据网络,但提供商只允许您使用Facebook、WhatsApp等应用程序而不是其他网站,那么同样的情况也会发生。这些验证只是让您能够快速告诉用户他没有连接上,而不是让他/她等待超时。我认为,必须进行两个检查:数据连接可用性加上“互联网”可用性。 - Jahaziel

14

还有一点很重要的提示。为了使其正常工作,您必须在AndroidManifest.xml中设置android.permission.ACCESS_NETWORK_STATE

_我该如何在在线文档中找到所需信息?

您只需要仔细阅读类的文档,就能找到所有您要寻找的答案。查看ConnectivityManager上的文档。说明会告诉您该怎么做。


13
ConnectivityManager类的描述并没有告诉我如何使用这个类,它只是列出了方法签名和常量值。这个问题的答案中提供的信息比文档中的更详细。文档中没有提到getActiveNetworkInfo()可能会返回null,也没有提到需要拥有ACCESS_NETWORK_STATE权限等。除了Android源代码,你从哪里找到这些信息呢? - dfjacobs
3
好观点,dfjacobs。现在似乎缺乏像样的示例,因此Stackoverflow成为了首选的来源。 - Steven
在此处说明了需要ACCESS_NETWORK_STATE权限:https://developer.android.com/reference/android/net/ConnectivityManager.html#getActiveNetworkInfo()。 - jk7

12

ConnectivityManager的getActiveNetworkInfo()方法会返回一个NetworkInfo实例,该实例代表第一个可用的连接网络接口,如果没有任何接口连接,则返回null。检查此方法是否返回null就足以判断是否有可用的互联网连接。

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

您还需要:

在Android清单中添加。

编辑:

请注意,拥有活动网络接口并不能保证特定的网络服务可用。网络问题、服务器停机、信号低、被困门户网站、内容过滤等都可能阻止您的应用程序访问服务器。例如,在收到来自Twitter服务的有效响应之前,您无法确定您的应用程序是否可以访问Twitter。

getActiveNetworkInfo()永远不应返回null。我不知道他们当时想的是什么。它应该始终返回一个对象。


如果没有单个活动连接,为什么要返回一个对象呢? - David Liu

10

可能我已经找到了自己:

ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
return connectivityManager.getActiveNetworkInfo().isConnectedOrConnecting();

12
如果没有活动网络,例如在飞行模式下,getActiveNetworkInfo()可能返回null。 - Alex Jasmin
3
是的,它将返回 null,而且这是未记录的。 - w.donahue
1
是的,所以首先要进行空值检查 activeNetwork != null && activeNetwork.isConnectedOrConnecting(); - GraSim
我喜欢这一行代码: boolean isWifiConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting() && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI; - Erich García
有人能详细解释一下这行代码吗?看起来对我来说很奇怪:first activeNetwork != null。 - TheLearner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接