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

当前回答

更新29/06/2015 如果你正在使用Xamarin。Android和想要检查连接,你可以使用Nuget包,这将给你在多个平台上的功能。好的候选人在这里和这里。 [更新结束]

The Answers above are quite good, but they are all in Java, and almost all of them check for a connectivity. In my case, I needed to have connectivity with a specific type of connection and I am developing on Xamarin.Android. Moreover, I do not pass a reference to my activities Context in the Hardware layer, I use the Application Context. So here is my solution, in case somebody comes here with similar requirements. I have not done full testing though, will update the answer once I am done with my 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
    }

其他回答

使用以下方法检查互联网连接,同时ConnectivityManager.getActiveNetworkInfo()在API 28中已弃用

@Suppress("DEPRECATION")
fun isNetworkConnected(context: Context): Boolean {
    val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
    return cm?.run {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            cm.getNetworkCapabilities(cm.activeNetwork)?.run {
                when {
                    hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                    hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                    hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                    else -> false
                }
            }
        } else {
            cm.activeNetworkInfo?.run {
                when (type) {
                    ConnectivityManager.TYPE_WIFI -> true
                    ConnectivityManager.TYPE_MOBILE -> true
                    else -> false
                }
            }
        }
    } ?: false

}

还要向清单添加以下权限

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

hatransport_ethernet (NetworkCapabilities.TRANSPORT_ETHERNET)用于为Android TV开发的应用程序,其中TV可以直接连接到以太网

如果您正在使用API 23或更高版本,您现在可以使用NetworkCapabilities检查internet是否处于活动状态。net_capacity_validated,由谷歌自己的ping服务支持。

ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
    @Override
    public void onLost(Network network) {
        // handle network lost
    }

    @Override
    public void onAvailable(Network network) {
        ConnectivityManager cm = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = cm.getNetworkInfo(network);
        boolean isConnected = (info != null && info.isConnectedOrConnecting());

        if (isConnected) {
            NetworkCapabilities nc = cm.getNetworkCapabilities(network);
            if (nc != null) {
                boolean isInternetValid = nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
                if (isInternetValid) {
                    // internet is valid
                }
            }
        }
    }
};

NetworkRequest request = new NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.registerNetworkCallback(request, networkCallback);

可以通过该方法检测网络可用性-

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

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

芬兰湾的科特林实现

/**
* Function that uses ping, takes server name or ip as argument.
*
* @return [Double.MAX_VALUE] if server is not reachable. Average RTT if the server is reachable.
*
* Success output example
*
* PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
* 64 bytes from 8.8.8.8: icmp_seq=1 ttl=254 time=172 ms
* 64 bytes from 8.8.8.8: icmp_seq=2 ttl=254 time=166 ms
* 64 bytes from 8.8.8.8: icmp_seq=3 ttl=254 time=167 ms
* 64 bytes from 8.8.8.8: icmp_seq=4 ttl=254 time=172 ms
* 64 bytes from 8.8.8.8: icmp_seq=5 ttl=254 time=167 ms

* --- 8.8.8.8 ping statistics ---
* 5 packets transmitted, 5 received, 0% packet loss, time 4011ms
* rtt min/avg/max/mdev = 166.470/169.313/172.322/2.539 ms
*          |________________________|
* value to parse using it.split('=')[1].trim().split(' ')[0].trim().split('/')[1].toDouble()
*/
@ExperimentalStdlibApi
fun pingServerAverageRtt(host: String): Double {

    var aveRtt: Double = Double.MAX_VALUE

    try {
        // execute the command on the environment interface, timeout is set as 0.2 to get response faster.
        val pingProcess: Process = Runtime.getRuntime().exec("/system/bin/ping -i 0.2 -c 5 $host")
        // gets the input stream to get the output of the executed command
        val bufferedReader = BufferedReader(InputStreamReader(pingProcess.inputStream))

        bufferedReader.forEachLine {
            if (it.isNotEmpty() && it.contains("min/avg/max/mdev")) {  // when we get to the last line of executed ping command
                aveRtt = it.split('=')[1].trim()
                        .split(' ')[0].trim()
                        .split('/')[1].toDouble()
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }

    return aveRtt
}

使用的例子


val latency = pingServerAverageRtt(ipString)
if (latency != Double.MAX_VALUE) { 
    //server reachable
} else {
    //server not reachable
}