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

当前回答

我在这里看到了很多过时的答案,所以我决定加入我的答案。

由于Android 10 (API级别29)getActiveNetworkInfo()已弃用,谷歌建议我们使用NetworkCallbacks而不是针对Android 10及更高版本的应用程序。

关于阅读网络状态的文档提供了一些关于如何使用NetworkCallback的信息,但我没有设法找到一个很好的代码示例,整个事情的工作,所以这里是我提出的代码,我们在我们的应用程序中使用:

import android.content.Context
import android.net.ConnectivityManager
import android.net.LinkProperties
import android.net.Network
import android.net.NetworkCapabilities
import com.fieldontrack.kmm.common.network.ConnectivityMonitor
import com.fieldontrack.kmm.entities.connectivity.NetworkType
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

class ConnectivityMonitorImpl(appContext: Context) : ConnectivityMonitor {
    private val connectivityManager = appContext.getSystemService(ConnectivityManager::class.java)
    private val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) =
            connectivityManager.getNetworkCapabilities(network)?.let { networkCapabilities ->
                updateConnectionStatus(networkCapabilities = networkCapabilities)
                updateNetworkType(networkCapabilities = networkCapabilities)
            } ?: run {
                _isConnectedState.value = true
            }

        override fun onLost(network: Network) {
            // Do not check for NetworkCapabilities here, as they might be wrong.
            // If we get this callback, we're certain that we've lost connection.
            _isConnectedState.value = false
            _networkTypeState.value = NetworkType.Unknown
        }

        override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
        ) {
            updateConnectionStatus(networkCapabilities = networkCapabilities)
            updateNetworkType(networkCapabilities = networkCapabilities)
        }

        override fun onLinkPropertiesChanged(
            network: Network,
            linkProperties: LinkProperties
        ) = Unit
    }
    private val _isConnectedState = MutableStateFlow(false)
    private val _networkTypeState = MutableStateFlow(NetworkType.Unknown)

    override val isConnectedState: StateFlow<Boolean> = _isConnectedState
    override val networkTypeState: StateFlow<NetworkType> = _networkTypeState

    override val isConnected: Boolean
        get() = _isConnectedState.value

    override val networkType: NetworkType
        get() = _networkTypeState.value

    init {
        startMonitoring()
    }

    override fun startMonitoring() =
        connectivityManager.registerDefaultNetworkCallback(networkCallback)

    override fun stopMonitoring() =
        connectivityManager.unregisterNetworkCallback(networkCallback)

    private fun updateConnectionStatus(networkCapabilities: NetworkCapabilities) {
        val isConnected =
            networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)

        _isConnectedState.value = isConnected
    }

    private fun updateNetworkType(networkCapabilities: NetworkCapabilities) {
        val networkType = when {
            networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> NetworkType.WiFi
            networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> NetworkType.Cellular
            else -> NetworkType.Unknown
        }

        _networkTypeState.value = networkType
    }
}

ConnectivityMonitor界面非常简单:

interface ConnectivityMonitor {
    val isConnected: Boolean
    val networkType: NetworkType

    val isConnectedState: StateFlow<Boolean>
    val networkTypeState: StateFlow<NetworkType>
    
    fun startMonitoring()
    fun stopMonitoring()
}

NetworkType只是一个简单的枚举:

enum class NetworkType { Unknown, Cellular, WiFi }

据我测试,无论应用程序是在后台还是前台,这都是可行的。

其他回答

下面是我使用的方法:

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

这对我来说确实有用:

验证网络可用性。

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

以下是来自我的Utils类的代码:

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

不要忘记将这些权限添加到您的manifest:

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

The other answers that use ConnectivityManager are wrong because having a network connection doesn't mean you have internet access. For example, the user might be connected to a coffee shop's WiFi portal but can't get to the internet. To check that the internet is accessible you have to try to connect to an actual server. Normally when you want to do this you have a specific server in mind that you want to connect to, so go ahead and check if you can connect to that server. Here's a simple method for checking connectivity to a server.

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不允许你在主线程上运行这个程序。