如何在Android上检查互联网访问?InetAddress 永远不会超时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1560788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to check internet access on Android? InetAddress never times out
提问by Vidar Vestnes
I got a AsyncTask
that is supposed to check the network access to a host name. But the doInBackground()
is never timed out. Anyone have a clue?
我得到了一个AsyncTask
应该检查对主机名的网络访问。但是doInBackground()
永远不会超时。有人有线索吗?
public class HostAvailabilityTask extends AsyncTask<String, Void, Boolean> {
private Main main;
public HostAvailabilityTask(Main main) {
this.main = main;
}
protected Boolean doInBackground(String... params) {
Main.Log("doInBackground() isHostAvailable():"+params[0]);
try {
return InetAddress.getByName(params[0]).isReachable(30);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
protected void onPostExecute(Boolean... result) {
Main.Log("onPostExecute()");
if(result[0] == false) {
main.setContentView(R.layout.splash);
return;
}
main.continueAfterHostCheck();
}
}
采纳答案by Levite
Network connection / Internet access
网络连接/互联网访问
isConnectedOrConnecting()
(used in most answers) checks for any networkconnection- To know whether any of those networks have internetaccess, use one of the following
isConnectedOrConnecting()
(在大多数答案中使用)检查任何网络连接- 要了解这些网络中是否有任何一个可以访问Internet,请使用以下方法之一
A) Ping a Server (easy)
A) Ping 一个服务器(简单)
// ICMP
public boolean isOnline() {
Runtime runtime = Runtime.getRuntime();
try {
Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
int exitValue = ipProcess.waitFor();
return (exitValue == 0);
}
catch (IOException e) { e.printStackTrace(); }
catch (InterruptedException e) { e.printStackTrace(); }
return false;
}
+
could run on main thread
+
可以在主线程上运行
-
does not work on some old devices (Galays S3, etc.), it blocks a while if no internet is available.
-
不适用于某些旧设备(Galays S3 等),如果没有互联网可用,它会阻塞一段时间。
B) Connect to a Socket on the Internet (advanced)
B) 连接到 Internet 上的 Socket(高级)
// TCP/HTTP/DNS (depending on the port, 53=DNS, 80=HTTP, etc.)
public boolean isOnline() {
try {
int timeoutMs = 1500;
Socket sock = new Socket();
SocketAddress sockaddr = new InetSocketAddress("8.8.8.8", 53);
sock.connect(sockaddr, timeoutMs);
sock.close();
return true;
} catch (IOException e) { return false; }
}
+
very fast (either way), works on all devices, veryreliable
+
非常快(无论哪种方式),适用于所有设备,非常可靠
-
can't run on the UI thread
-
无法在 UI 线程上运行
This works very reliably, on every device, and is very fast. It needs to run in a separate task though (e.g. ScheduledExecutorService
or AsyncTask
).
这在每个设备上都非常可靠,并且速度非常快。它需要在单独的任务中运行(例如ScheduledExecutorService
或AsyncTask
)。
Possible Questions
可能的问题
Is it really fast enough?
Yes, very fast ;-)
Is there no reliable way to check internet, other than testing something on the internet?
Not as far as I know, but let me know, and I will edit my answer.
What if the DNS is down?
Google DNS (e.g.
8.8.8.8
) is the largest public DNS in the world. As of 2013 it served 130 billion requests a day. Let 's just say, your app would probably not be the talk of the day.Which permissions are required?
<uses-permission android:name="android.permission.INTERNET" />
Just internet access - surprise ^^ (Btw have you ever thought about, how some of the methods suggested here could even have a remote glue about internet access, without this permission?)
真的够快吗?
是的,非常快;-)
除了在互联网上测试某些东西之外,没有可靠的方法来检查互联网吗?
据我所知,但让我知道,我会编辑我的答案。
如果 DNS 关闭怎么办?
Google DNS(例如
8.8.8.8
)是世界上最大的公共 DNS。截至 2013 年,它每天处理 1300 亿个请求。我们只是说,您的应用程序可能不会成为今天的话题。需要哪些权限?
<uses-permission android:name="android.permission.INTERNET" />
只是互联网访问 - 惊喜^^(顺便说一句,你有没有想过,如果没有这个许可,这里建议的一些方法甚至可以远程连接互联网访问?)
Extra: One-shot AsyncTask
Example
补充:一次性AsyncTask
示例
class InternetCheck extends AsyncTask<Void,Void,Boolean> {
private Consumer mConsumer;
public interface Consumer { void accept(Boolean internet); }
public InternetCheck(Consumer consumer) { mConsumer = consumer; execute(); }
@Override protected Boolean doInBackground(Void... voids) { try {
Socket sock = new Socket();
sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
sock.close();
return true;
} catch (IOException e) { return false; } }
@Override protected void onPostExecute(Boolean internet) { mConsumer.accept(internet); }
}
///////////////////////////////////////////////////////////////////////////////////
// Usage
new InternetCheck(internet -> { /* do something with boolean response */ });
Extra: One-shot RxJava/RxAndroid
Example (Kotlin)
额外:一次性RxJava/RxAndroid
示例(Kotlin)
fun hasInternetConnection(): Single<Boolean> {
return Single.fromCallable {
try {
// Connect to Google DNS to check for connection
val timeoutMs = 1500
val socket = Socket()
val socketAddress = InetSocketAddress("8.8.8.8", 53)
socket.connect(socketAddress, timeoutMs)
socket.close()
true
} catch (e: IOException) {
false
}
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
///////////////////////////////////////////////////////////////////////////////////
// Usage
hasInternetConnection().subscribe { hasInternet -> /* do something */}
回答by gar
If the device is in airplane mode (or presumably in other situations where there's no available network), cm.getActiveNetworkInfo()
will be null
, so you need to add a null
check.
如果设备处于飞行模式(或者可能在没有可用网络的其他情况下),cm.getActiveNetworkInfo()
则将是null
,因此您需要添加一个null
检查。
Modified (Eddie's solution) below:
修改(埃迪的解决方案)如下:
public boolean isOnline() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
return netInfo != null && netInfo.isConnectedOrConnecting();
}
Also add the following permission to the AndroidManifest.xml
:
还要向 中添加以下权限AndroidManifest.xml
:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
One other small point, if you absolutely need a network connection at the given point in time, then it might be better to use netInfo.isConnected()
rather than netInfo.isConnectedOrConnecting
. I guess this is up to the individual use-case however.
另外一个小点,如果你绝对需要在给定时间点的网络连接,那么它可能是更好地使用netInfo.isConnected()
,而不是netInfo.isConnectedOrConnecting
。但是,我想这取决于个人用例。
回答by Eddie
No need to be complex. The simplest and framework manner is to use ACCESS_NETWORK_STATE
permission and just make a connected method
无需复杂。最简单的框架方式就是使用ACCESS_NETWORK_STATE
权限,只做一个连接的方法
public boolean isOnline() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null &&
cm.getActiveNetworkInfo().isConnectedOrConnecting();
}
You can also use requestRouteToHost
if you have a particualr host and connection type (wifi/mobile) in mind.
requestRouteToHost
如果您有特定的主机和连接类型(wifi/移动),您也可以使用。
You will also need:
您还需要:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
in your android manifest.
在你的安卓清单中。
回答by azelez
To get getActiveNetworkInfo()
to work you need to add the following to the manifest.
要开始getActiveNetworkInfo()
工作,您需要将以下内容添加到清单中。
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
回答by Chinmay Kanchi
Take a look at the ConnectivityManager class. You can use this class to get information on the active connections on a host. http://developer.android.com/reference/android/net/ConnectivityManager.html
查看 ConnectivityManager 类。您可以使用此类来获取有关主机上活动连接的信息。http://developer.android.com/reference/android/net/ConnectivityManager.html
EDIT: You can use
编辑:您可以使用
Context.getSystemService(Context.CONNECTIVITY_SERVICE)
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
or
或者
Context.getSystemService(Context.CONNECTIVITY_SERVICE)
.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
and parse the DetailedState enum of the returned NetworkInfo object
并解析返回的 NetworkInfo 对象的详细状态枚举
EDIT EDIT: To find out whether you can access a host, you can use
编辑 编辑:要了解您是否可以访问主机,您可以使用
Context.getSystemService(Context.CONNECTIVITY_SERVICE)
.requestRouteToHost(TYPE_WIFI, int hostAddress)
Obviously, I'm using Context.getSystemService(Context.CONNECTIVITY_SERVICE) as a proxy to say
显然,我使用 Context.getSystemService(Context.CONNECTIVITY_SERVICE) 作为代理说
ConnectivityManager cm = Context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.yourMethodCallHere();
回答by Gilbou
check this code... it worked for me :)
检查此代码...它对我有用:)
public static void isNetworkAvailable(final Handler handler, final int timeout) {
// ask fo message '0' (not connected) or '1' (connected) on 'handler'
// the answer must be send before before within the 'timeout' (in milliseconds)
new Thread() {
private boolean responded = false;
@Override
public void run() {
// set 'responded' to TRUE if is able to connect with google mobile (responds fast)
new Thread() {
@Override
public void run() {
HttpGet requestForTest = new HttpGet("http://m.google.com");
try {
new DefaultHttpClient().execute(requestForTest); // can last...
responded = true;
}
catch (Exception e) {
}
}
}.start();
try {
int waited = 0;
while(!responded && (waited < timeout)) {
sleep(100);
if(!responded ) {
waited += 100;
}
}
}
catch(InterruptedException e) {} // do nothing
finally {
if (!responded) { handler.sendEmptyMessage(0); }
else { handler.sendEmptyMessage(1); }
}
}
}.start();
}
Then, I define the handler:
然后,我定义处理程序:
Handler h = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what != 1) { // code if not connected
} else { // code if connected
}
}
};
...and launch the test:
...并启动测试:
isNetworkAvailable(h,2000); // get the answser within 2000 ms
回答by Ajhar
Found at and modified (!) from this link:
在此链接中找到并修改(!):
In your manifest file add at least:
在您的清单文件中至少添加:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
You probably already have the INTERNET permission if you are accessing it. Then a boolean function that allows to test for connectivity is:
如果您正在访问它,您可能已经拥有 INTERNET 权限。然后允许测试连通性的布尔函数是:
private boolean checkInternetConnection() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
// test for connection
if (cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isAvailable()
&& cm.getActiveNetworkInfo().isConnected()) {
return true;
} else {
Log.v(TAG, "Internet Connection Not Present");
return false;
}
}
回答by Android.Thirio.nl
I made this code, it is the simplest and it is just a boolean.
by asking if(isOnline()){
我做了这个代码,它是最简单的,它只是一个布尔值。通过询问if(isOnline()){
You get if there is a connection and if it can connect to a page the status code 200
(stable connection).
如果有连接,如果它可以连接到页面,您将获得状态代码200
(稳定连接)。
Make sure to add the correct INTERNET
and ACCESS_NETWORK_STATE
permissions.
确保添加正确的INTERNET
和ACCESS_NETWORK_STATE
权限。
public boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
try {
URL url = new URL("http://www.google.com");
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
urlc.setConnectTimeout(3000);
urlc.connect();
if (urlc.getResponseCode() == 200) {
return new Boolean(true);
}
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return false;
}
回答by Musculaa
It does works for me:
它对我有用:
To verify network availability:
要验证网络可用性:
private Boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting();}
To verify internet access:
要验证互联网访问:
public Boolean isOnline() {
try {
Process p1 = java.lang.Runtime.getRuntime().exec("ping -c 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
return reachable;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
回答by Mohamed Embaby
There's more than one way
方法不止一种
First, shortest but Inefficient way
一、最短但效率低下的方式
Network State Permission only needed
只需要网络状态权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Then this method,
那么这个方法,
public boolean activeNetwork () {
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnected();
return isConnected;
}
As seen in answers ConnectivityManager
is a solution, I just added it within a method this is a simplified method all useConnectivityManager
returns true if there is a network access not Internet access, means if your WiFi is connected to a router but the router has no internet it returns true, it check connection availability
正如在回答看到ConnectivityManager
一个解决方案,我只是增加了它的方法中,这是一个简化的方法都用ConnectivityManager
返回true,如果有网络访问不上网,也就是说,如果您的WiFi连接到路由器,但路由器有没有互联网它返回 true,它检查连接可用性
Second, Efficient way
二、高效方式
Network State and Internet Permissions needed
需要网络状态和 Internet 权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
Then this class,
那么这堂课,
public class CheckInternetAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private Context context;
public CheckInternetAsyncTask(Context context) {
this.context = context;
}
@Override
protected Boolean doInBackground(Void... params) {
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
assert cm != null;
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnected();
if (isConnected) {
try {
HttpURLConnection urlc = (HttpURLConnection)
(new URL("http://clients3.google.com/generate_204")
.openConnection());
urlc.setRequestProperty("User-Agent", "Android");
urlc.setRequestProperty("Connection", "close");
urlc.setConnectTimeout(1500);
urlc.connect();
if (urlc.getResponseCode() == 204 &&
urlc.getContentLength() == 0)
return true;
} catch (IOException e) {
Log.e("TAG", "Error checking internet connection", e);
return false;
}
} else {
Log.d("TAG", "No network available!");
return false;
}
return null;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
Log.d("TAG", "result" + result);
if(result){
// do ur code
}
}
}
Call CheckInternetAsyncTask
称呼 CheckInternetAsyncTask
new CheckInternetAsyncTask(getApplicationContext()).execute();
Some Explanations :-
一些解释:-
you have to check Internet on
AsyncTask
, otherwise it can throwandroid.os.NetworkOnMainThreadException
in some casesConnectivityManager
used to check the network access if true sends request (Ping)Request send to
http://clients3.google.com/generate_204
, This well-known URL is known to return an empty page with an HTTP status 204 this is faster and more efficient thanhttp://www.google.com
, read this. if you have website it's preferred to put you website instead of google, only if you use it within the appTimeout can be changed range (20ms -> 2000ms), 1500ms is commonly used
你必须检查互联网
AsyncTask
,否则android.os.NetworkOnMainThreadException
在某些情况下它会抛出ConnectivityManager
用于检查网络访问是否为 true 发送请求(Ping)请求发送到
http://clients3.google.com/generate_204
,这个众所周知的 URL 会返回一个带有 HTTP 状态 204 的空页面,这比http://www.google.com
阅读这个更快、更有效。如果你有网站,最好把你的网站放在你的网站上而不是谷歌上,只有当你在应用程序中使用它时超时可更改范围(20ms -> 2000ms),常用1500ms