我得到了一个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();
}
}
这里是检查互联网连接的最佳方法。这个方法所做的是执行一系列检查“手机是否处于飞行模式,手机是否连接到网络,等等”。如果所有检查都返回true,该方法将从互联网下载一个文件,并查看内容是否与预期值匹配。
与其他通过ping服务器来检查互联网连接的方法相比,这种方法的好处是:
Android运行时在不同的手机上是不同的-所以你可能并不总是能够执行这些命令,如下所示:为什么ping在一些设备上工作,而不是其他设备?
ping服务器并不总是有效,因为登录页面/重定向在wifi网络上,这可能会给人一种连接的错误印象。
这个答案是用Kotlin写的,并使用Fuel库从互联网上下载一个文件,使用methodfetchUrlAsString,但是任何库都可以被替换,只要你确保你的HTTP请求没有被缓存。可以将showConnectionWarning()和hideConnectionWarning()分别等价于互联网连接状态= false和互联网连接状态= true。
private val networkReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val activeNetworkInfo = (context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo
if (activeNetworkInfo != null) {
if (activeNetworkInfo.isConnectedOrConnecting) {
//Launches a coroutine to fetch file asynchronously
launch {
try {
//Downloads file from url on the internet - use any library you want here.
val connectionStatus = fetchUrlAsString(<url_for_file_on_internet>)
//check if the contents of the file is as expected
if (connectionStatus == "Connected To Database") {
hideConnectionWarning()
} else {
showConnectionWarning()
}
} catch (e: Exception) {
//Catches an exception - fetchUrlAsString only throws an exception if there is no internet
showConnectionWarning()
}
}
} else {
showConnectionWarning()
}
} else {
showConnectionWarning()
}
}
}
private suspend fun fetchUrlAsString(url: String): String = suspendCoroutine { cont ->
url.httpGet().header(Pair("pragma", "no-cache"), Pair("cache-control", "no-cache")).responseString { _, _, result ->
when (result) {
is Result.Failure -> {
cont.resumeWithException(result.getException())
}
is Result.Success -> {
cont.resume(result.value)
}
}
}
}
您将需要以下权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
我已经应用了@Levit提供的解决方案,并创建了不会调用额外Http请求的函数。
它将解决无法解析主机的错误
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
}
下面是我使用的方法:
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
我已经经历了所有的答案,我想出了我自己的答案,首先检查互联网是否可用,如果互联网可用,然后检查它是否活跃。
我已经包括了所有必要的方法和类来检查活跃的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();
}
}
你可以使用下面的代码检查互联网是否活跃:
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);
}
});
}
我已经尝试了近5+不同的android方法,发现这是谷歌提供的最佳解决方案,特别是android:
try {
HttpURLConnection urlConnection = (HttpURLConnection)
(new URL("http://clients3.google.com/generate_204")
.openConnection());
urlConnection.setRequestProperty("User-Agent", "Android");
urlConnection.setRequestProperty("Connection", "close");
urlConnection.setConnectTimeout(1500);
urlConnection.connect();
if (urlConnection.getResponseCode() == 204 &&
urlConnection.getContentLength() == 0) {
Log.d("Network Checker", "Successfully connected to internet");
return true;
}
} catch (IOException e) {
Log.e("Network Checker", "Error checking internet connection", e);
}
它比任何其他可用的解决方案都更快、高效和准确。