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


657

我得到了一个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();
    }   
}

5
要检查Internet连接,最可靠的方法可能是ping一台主要的名称服务器,例如,可以使用来完成if(Runtime.getRuntime().exec("/system/bin/ping -c 1 8.8.8.8").waitFor()==0) ...。请参阅我的答案以获得更好的实现。顺便说一句(这里还有很多其他答案),只是检查网络连接,而不是互联网。
莱维特2014年


4
不要使用ping方法,而应使用HTTP检查。ICMP在某些网络上被阻止,因此无法ping通。例如:它可以在我的家庭wifi上完美运行,但是当我在沃达丰(匈牙利)的网络上使用移动数据时却无法使用。或将这两种方法结合起来作为备用方法,但是要小心,因为即使使用-w或-W,waitFor()也会等待约20秒。
陶Bolvári


@TamásBolvári:更好的办法是在tcp层解决它。凭借HTTP请求的可靠性,这应该使您接近ICMP的速度。我相应地编辑了“ ping答案”。
Levite

Answers:


551

网络连接/互联网访问

  • isConnectedOrConnecting()(用于大多数答案)检查是否有网络连接
  • 要了解这些网络中是否有互联网可以使用,请使用以下方法之一

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上的套接字(高级)

// 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。截至2013年,它每天处理1300亿个请求。只是说,您的应用可能不会成为今天的话题。

  • 需要哪些权限?

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

    只是Internet访问-令人惊讶^^(顺便说一句,您是否曾想过,如果没有此许可,此处建议的某些方法甚至可能对Internet访问产生远程影响?)

 

额外:单发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 */ });

附加:单发RxJava/RxAndroid示例(科特琳)

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

22
这是伟大的代码和平!我发现它在使用预付卡的设备上非常有用!当他们的钱用完时,他们可以使用互联网,但是没有互联网。因此,仅检查连通性是行不通的。谢谢!
Blejzer

10
请记住,这种方法是一种阻塞性方法,因此您不应在UI therad中执行它
Sergii

36
@Levit这应该是公认的答案。上面的答案只是检查网络n 不是Internet连接。是的,这非常快。谢谢。因此投票。
Roon13年5

9
此解决方案不适用于所有设备。如@Salmaan所述,某些设备始终返回2。我测试的设备具有Internet连接,并且ping目标是Google DNS服务器-它正在响应ping请求。我认为某些供应商不允许ping请求。例如,我使用三星10.1平板电脑(4.3)进行了测试,但该解决方案无法正常工作。通过命令行实用程序运行ping命令时,出现权限错误。该命令在仿真器上也不起作用。使用此解决方案时要小心。
Eren Yilmaz 2015年

9
此方法不适用于所有手机。例如,它在三星Galaxy S3上失败。请参阅此处:为什么ping只能在某些设备上工作而不能在其他设备上工作?
阿迪尔·侯赛因

1032

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

修改如下(Eddie的解决方案):

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。我想这取决于单个用例。


109
imo您仍然应该并且需要检查http超时异常,因为在某些情况下可能已连接网络,但实际上没有Internet连接,因为访问它的唯一方法是通过例如VPN-这样,您就可以例如WI-FI连接,但没有实际的互联网流量。另一种情况是服务器挂起。这是我最近运行的2个问题,而连接管理器在此无济于事。
2012年

21
我同意午夜和Pintu,这个答案不应该是公认的答案,它与检查您是否在互联网上无关。例如,如果电话通过强制门户连接到WiFi网络(例如在酒店),则此功能将错误地返回true。正确的答案是在公用Internet上ping服务器。
miguel 2014年

9
当路由器没有可用的互联网时,如果我通过wifi连接到路由器,则上面的代码将返回true。但是,不应该是吧?你能帮我
磨憨ķ拉吉

5
我必须添加上下文,context.getSystemService否则它不起作用。我在这里得到了提示androidhive.info/2012/07/…–
Francisco Corrales Morales

1
检查网络可用性的好方法。但是如何检查互联网访问?
陶Bolvári

296

无需复杂。最简单的框架方式是使用ACCESS_NETWORK_STATE权限,然后创建一个连接方法

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

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

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

您还需要:

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

在您的Android清单中。


82
最好在cm.getActiveNetworkInfo()级别执行空检查,如果没有活动的网络可用,则将其抛出空。
塞缪尔

看到stackoverflow.com/a/11691676/1979773约requestRouteToHost()更深exaplanation
Spartako

我必须添加上下文,context.getSystemService否则它不起作用。我在这里知道了androidhive.info/2012/07/…–
Francisco Corrales Morales

9
如果您连接到WiFi热点,即使该热点没有Internet连接,此解决方案也将返回true。
2015年


63

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

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

绝对应该在正确的答案下(浪费太多时间弄清楚到底是怎么了)。
IndrekKõue2011年

2
为此,不需要INTERNET许可,只需ACCESS_NETWORK_STATE。仅当您实际上是在与远程位置建立连接而不查询设备无线电的状态时才需要INTERNET。
汤姆(Tom)

3
您的答案目前并不是真正的答案,只是其他答案的一个相对较小的补充。如果其他所有答案都不在这里,您的答案有意义吗?并不是的。因为如果这样,最好使用有关如何使用它的代码扩展您的答案,或者删除您的答案并将信息添加到另一个答案中(您将不会失去任何声誉)
Tim

要小心,getActiveNetworkInfo()在API级别29.弃用
堆栈溢出

46

看一下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对象的DetailedState枚举

编辑:要查明是否可以访问主机,可以使用

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发出请求...
Vidar Vestnes

1
在EDIT EDIT部分中有一个错误,我忽略了requestRouteToHost()调用。立即重新阅读答案:)
Chinmay Kanchi,2009年

requestRouteToHost已被弃用。
Jahaziel

46

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

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

3
Google怎么了?这也需要INTERNET权限,这对于给定的任务是不必要的。最后,这会消耗数据(即使微不足道)。这似乎是一个大错。
汤姆(Tom)

28
@Tom说句公道话,这可能是唯一正确的答案。其他示例仅显示网络连接是否可用和/或是否存在与该网络的连接,但是没有回答该网络是否实际上也可以进行远程连接(例如与网站)的问题。所以这个答案的海报Q,以及其他的答案不
slinden77

2
@dmmh是的,不幸的是,根据我在Android API中看到的情况,这是正确的。一个简单的ping可能更好,stackoverflow.com/questions/3905358/…。如果您真的很担心,甚至可以列出要查验的IP地址,因为虽然Google宕机的可能性很小,但Google,Bing和Yahoo在同一天宕机的可能性更小。只是我的想法。
汤姆

10
进行此检查没有任何意义。如果您要花费系统时间和网络资源来连接到Google,则可以花费它们来连接到您真正关心的资源。
本杰明·

16
在中国,谷歌被封锁了!!
2014年

26

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

在清单文件中至少添加:

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

18

我编写了这段代码,它是最简单的,只是一个布尔值。通过询问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;
}

6
也许您应该将200替换为HttpURLConnection.HTTP_OK
Yash

5
如果Google倒闭怎么办?
Yauraw Gadav

12

它对我有用:

要验证网络可用性:

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

这是检查服务器是否正常运行的好方法。谢谢!
Williew 2014年

1
isOnline()根本不应在主线程上运行,就好像有wi-fi信号但没有互联网连接一样,它将花费太长时间并阻塞主线程。
2015年

9

有不止一种方法

首先,最短但效率低下的方式

仅需要网络状态权限

<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是一个解决方案,我只是在一个方法中添加了它,这是一种简化的方法,
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();

一些解释:

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

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

  • 发送请求http://clients3.google.com/generate_204,这个著名的URL是已知的HTTP状态204返回一个空白页面,这是更快,更高效比http://www.google.com,看这个。如果您拥有网站,则最好仅在应用程序中使用它,而不是Google来放置您的网站

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


2
很好的问题,可悲的是您没有更多的积分。这必须是正确的答案。
Jhon Fredy Trujillo Ortega,

我是Android新手。虽然,这是一个覆盖面很广的答案,它会引起更多关注@ 7569106
Mazen Embaby

1
最佳和完整的答案,谢谢。如果某人有一个网站通知,则条件必须类似于此urlc.getResponseCode()== 200,而无需检查urlc.getContentLength()== 0
AREF

您的第二个选择会崩溃,我不知道为什么
nafees ahmed 18-11-13

它冻结了应用程序
nafees ahmed

8

到目前为止,我所见过的一切中最短最干净的方法应该是:

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中传递Context。谢谢!
RyanG 2012年

8

这是我使用的方法:

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


7

移动设备上的一个重要用例可确保存在实际的连接。当移动用户使用“强制门户”进入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;
}

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

6

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

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

6

对我来说,在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字符串作为响应)


6

对我有用。试试看。

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

由于我们现在无法访问主线程上的网络,因此该答案现在无法正常工作。
正宗白布鞋

1
我的意思是从API级别11开始,这不起作用。原因:developer.android.com/reference/android/os/…。如果它适合您,则表示您正在旧的android设备上运行此代码。(GB之前)。
正宗白布鞋

StrictMode.ThreadPolicy策略=新的StrictMode.ThreadPolicy.Builder().permitAll()。build(); StrictMode.setThreadPolicy(policy); 将这两行添加到您的程序中,以避免网络主线程异常
selva_pollachi 2013年

好的,我不应该说这行不通,我应该说它可以行(通过目标旧版本或Strictmode设置),但是不建议这样做。这可能容易导致ANR。(在httpurlconnection中具有如此高的超时配置)
正宗白布鞋

是的..你是对的..我只说了这一点,因为这也是其中一种方式。
selva_pollachi 2013年

6

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

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

5

我正在使用此代码而不是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是否意味着没有互联网连接以及它的可靠性,那将是很棒的。
Milad.Nozari 2015年

5

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

有关更多详细信息,请访问 如何检查Android网络/ Internet连接状态。


5

最佳方法:

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

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

1
我喜欢这种方法,但是我必须指出一些事情。isReachable()返回一个布尔值,因此您可以像布尔值连接= InetAddress.getByName(“ google.com”)。isReachable(3)一样,而不是在try部分中返回true。然后返回连接。另外,isReacheable会引发IOException和IllegalArgumentException异常,因此,用IllegalArgumentException替换UnknownHostException并包含第三个catch是一个好主意:catch(Exception E)。
Yash

2
但是,然后,isReachable使用可能需要root特权的ICMP并使用端口7,该端口通常在最新系统上没有正在运行的服务。因此,检查到在线服务的路由的最佳方法是通过常规TCP。因此投了反对票。
Yash

5

以下是我Utils班上的代码:

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

5
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。
Pedro Pombeiro 2014年

5

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

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

5

我已经应用了@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
}


4

我仔细阅读了所有答案,然后提出了自己的答案,该答案首先检查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中打包线程,因此“迫使”开发人员不要滥用您的方法
Ewoks

如果有条件,则要多去除一个。if(((NetworkUtils.isInternetActiveWithPing()== NetworkUtils.STATUS_CONNECTED)|| NetworkUtils.isInternetActiveWithInetAddress()){//执行网络操作} else {//错误消息}
Jawad Zeb

4

检查我们是否与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调用,只要将它们包装在错误处理中,您就会很快知道是否具有Internet连接
rangi

4

Kotlin和协程

我已经放在一个功能ViewModel,它具有viewModelScope。使用可观察的方式,LiveData我通知活动有关该连接的信息。

视图模型

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

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

                    withContext(Dispatchers.Main) {
                        _connection.value = true
                    }
                }
                catch(ex: IOException) {
                    withContext(Main) {
                        _connection.value = 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
         }
     }
  }

3

只需创建以下类即可检查互联网连接:

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

此类仅包含一个返回连接状态的布尔值的方法。因此,简单来说,如果该方法找到与Internet的有效连接,则返回值为true,否则,false如果找不到有效连接。

然后,MainActivity中的以下方法从前面描述的方法中调用结果,并提示用户采取相应的措施:

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

在上面的代码中,如果结果为false,(因此没有互联网连接,则将用户转到Android wi-fi面板,在该面板中,系统将提示他连接到wi-fi热点。


3

更新 2015年6月29日如果您使用的是Xamarin.Android,并且要检查连接性,则可以使用Nuget程序包,该程序包将在多个平台上提供此功能。好候选人在这里这里。[更新结束]

上面的答案是相当不错的,但是它们都是用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
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.