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

当前回答

Jetpack组成/芬兰湾的科特林

根据Levite的回答,我们可以在Jetpack Compose中使用这个组合:

val DNS_SERVERS = listOf("8.8.8.8", "1.1.1.1", "4.2.2.4")
const val INTERNET_CHECK_DELAY = 3000L
@Composable
fun InternetAwareComposable(
    dnsServers: List<String> = DNS_SERVERS,
    delay: Long = INTERNET_CHECK_DELAY,
    successContent: (@Composable () -> Unit)? = null,
    errorContent: (@Composable () -> Unit)? = null,
    onlineChanged: ((Boolean) -> Unit)? = null
) {
    suspend fun dnsAccessible(
        dnsServer: String
    ) = try {
        withContext(Dispatchers.IO) {
            Runtime.getRuntime().exec("/system/bin/ping -c 1 $dnsServer").waitFor()
        } == 0
    } catch (e: Exception) {
        false
    }

    var isOnline by remember { mutableStateOf(false) }
    LaunchedEffect(Unit) {
        while (true) {
            isOnline = dnsServers.any { dnsAccessible(it) }
            onlineChanged?.invoke(isOnline)
            delay(delay)
        }
    }
    if (isOnline) successContent?.invoke()
    else errorContent?.invoke()
}

其他回答

有不止一种编码方式真是太棒了。 下面是我的例子。

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

祝你好运。

在我目前所见过的所有方法中,最短、最干净的方法应该是:

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,一切正常,并且您的设备有互联网连接。

我已经尝试了近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);
  }

它比任何其他可用的解决方案都更快、高效和准确。

这在android文档中有涉及 http://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html

看一下ConnectivityManager类。您可以使用这个类来获取主机上活动连接的信息。http://developer.android.com/reference/android/net/ConnectivityManager.html

编辑:你可以使用

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .getNetworkInfo(ConnectivityManager.TYPE_MOBILE) 

or

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .getNetworkInfo(ConnectivityManager.TYPE_WIFI) 

并解析返回NetworkInfo对象的DetailedState枚举

EDIT EDIT:查看是否可以访问主机

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .requestRouteToHost(TYPE_WIFI, int hostAddress)

显然,我使用Context.getSystemService(Context.CONNECTIVITY_SERVICE)作为代理来表示

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