如何检查Android的互联网接入? InetAddress永远不会超时

我有一个AsyncTask应该检查networking对主机名的访问。 但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(); } } 

@Eddie。 只需对您的解决scheme进行一些小的修改 – 如果设备处于飞行模式(或者大概在没有可用networking的情况下), cm.getActiveNetworkInfo()将为null ,因此您需要添加null检查。

修改后的解决scheme

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

另一个小问题是,如果您在给定的时间点绝对需要networking连接,那么使用netInfo.isConnected()而不是netInfo.isConnectedOrConnecting可能会更好。 我想这是由个人使用情况决定的。

互联网与连接

  • 大多数答案在这里使用isConnectedOrConnecting检查任何networking连接
  • 如果这是你想要的,使用它,但是如果你想知道互联网访问,…

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

+可以在主线程上运行

-不适用于某些旧设备(请参阅评论),只能通过Internet连接快速使用

B.或连接到端口(高级)

 // 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 )中运行。 它工作得很好,虽然我。 推荐它!

可能的问题

  • 它真的够快吗?

    是的,非常快;-)

  • 有没有可靠的方法来检查互联网,除了在互联网上testing一些东西?

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

  • 如果DNSclosures,该怎么办?

    Google DNS(例如8.8.8.8 )是全球最大的公共DNS。 截至2013年,它每天提供1300亿个请求。 我们只是说,你的应用程序可能不会是一天的谈话。

  • 哪些权限是必需的?

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

    只是互联网接入 – 惊喜^^(顺便说一句,你有没有想过,如何在这里build议的一些方法甚至可以有一个关于互联网访问远程胶水,没有这种权限?)

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

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

你也可以使用requestRouteToHost如果你有一个requestRouteToHost主机和连接types(无线/移动)在脑海中。

您还需要:

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

在你的Android清单。

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

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

检查这个代码…它为我工作:)

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

…并启动testing:

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

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

并parsing返回的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(); 

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

在清单文件中至less添加:

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

如果您正在访问,您可能已经拥有INTERNET权限。 那么允许testing连通性的布尔函数是:

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

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

它适用于我:

validationnetworking可用性:

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

validation互联网访问:

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

我所见过的最短,最干净的方式应该是:

 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,虽然你没有互联网。
对于一个真正的testing,我会build议执行HttpHead请求(例如www.google.com),并检查状态,如果它的200 OK一切正常,您的设备有互联网连接。

在移动设备上的一个重要的使用案例,以确保存在实际的连接。 当移动用户进入带有“强制门户”的Wifinetworking时,这是一个常见的问题,他们需要login。我在后台使用该阻止function来确保连接存在。

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

您可以遍历所有networking连接,并检查是否至less有一个可用的连接:

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

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

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

应该在那里调用,或者你需要下压你的活动实例(上下文)到连接处理程序类,以便能够检查连接状态当没有可用的连接(WiFi,networking)我赶上UnknownHostExceptionexception:

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

通过这种方式,我可以在同一个类中处理这个案例(我的服务器总是使用jsonstring回应)

这对我很有用。 试试看。

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

这里是我使用的方法:

 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

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

检查Androidnetworking/互联网连接状态并不复杂。 下面的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; } } } 

有关更多详情,请访问如何检查Androidnetworking/ Internet连接状态

最佳方法:

 public static boolean isOnline() { try { InetAddress.getByName("google.com").isReachable(3); return true; } catch (UnknownHostException e){ return false; } catch (IOException e){ return false; } } 

以下是我的Utils类的代码:

 public static boolean isNetworkAvailable(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); return activeNetworkInfo != null && activeNetworkInfo.isConnected(); } 
 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(); } } 

您可以使用此方法来检测networking可用性 –

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

使用ConnectivityManager的其他答案是错误的,因为拥有networking连接并不意味着您可以访问Internet。 例如,用户可能连接到咖啡店的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不会让你在你的主线程上运行这个。

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

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

我已经应用了@Levit提供的解决scheme,并创build了不会调用额外的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 } 

只需创build以下类来检查互联网连接:

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

这个类只包含一个返回连接状态的布尔值的方法。 因此,简而言之,如果方法find到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."); } } 

在上面的代码中,如果结果是假的(因此没有互联网连接,用户被带到Android Wi-Fi面板,在那里他被提示连接到一个Wi-Fi热点。

更新29/06/2015如果您使用Xamarin.Android并且想要检查连通性,您可以使用一个Nuget包,这个包可以在多个平台上提供这个function。 好的候选人在这里 , 在这里 。 [更新结束]

上面的答案是相当不错的,但是它们都是用Java编写的,而且几乎所有这些都检查了连通性。 在我的情况下,我需要连接到一个特定types的连接,我正在开发Xamarin.Android。 而且,我不会在硬件层传递一个对我的活动Context的引用,我使用Application Context。 所以这里是我的解决scheme,以防有人来这里有类似的要求。 我还没有做完整的testing,一旦我完成了testing,就会更新答案

 using Android.App; using Android.Content; using Android.Net; namespace Leopard.Mobile.Hal.Android { public class AndroidNetworkHelper { public static AndroidNetworkStatus GetWifiConnectivityStatus() { return GetConnectivityStatus(ConnectivityType.Wifi); } public static AndroidNetworkStatus GetMobileConnectivityStatus() { return GetConnectivityStatus(ConnectivityType.Mobile); } #region Implementation private static AndroidNetworkStatus GetConnectivityStatus(ConnectivityType connectivityType) { var connectivityManager = (ConnectivityManager)Application.Context.GetSystemService(Context.ConnectivityService); var wifiNetworkInfo = connectivityManager.GetNetworkInfo(connectivityType); var result = GetNetworkStatus(wifiNetworkInfo); return result; } private static AndroidNetworkStatus GetNetworkStatus(NetworkInfo wifiNetworkInfo) { var result = AndroidNetworkStatus.Unknown; if (wifiNetworkInfo != null) { if (wifiNetworkInfo.IsAvailable && wifiNetworkInfo.IsConnected) { result = AndroidNetworkStatus.Connected; } else { result = AndroidNetworkStatus.Disconnected; } } return result; } #endregion } public enum AndroidNetworkStatus { Connected, Disconnected, Unknown } 
 public boolean isOnline() { boolean var = false; ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); if ( cm.getActiveNetworkInfo() != null ) { var = true; } return var; } 

I have done it this way. A little bit shorter and more readable I guess.

干杯!

Saiyan

 public static boolean isNetworkAvailable(Context ctx) { ConnectivityManager connMgr = (ConnectivityManager)ctx.getSystemService(Context.CONNECTIVITY_SERVICE); if(connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected() || connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isConnected()){ return true; } return false; } 

user this

Its so great to have more then one way to code. Here is my example.

 ConnectivityManager icheck = getSystemService(Context.CONNECTIVITY_SERVICE); TextView tv = findViewById(R.id.textView1); boolean wifi = icheck.getActiveNetworkInfo() != null; if(wifi) { tv.setText("Internet is on."); } else { tv.setText("Internet is off."); } 

祝你好运。