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

当前回答

下面是我用于可达性检查的Kotlin版本,

芬兰湾的科特林MyReachability

object MyReachability {

    private val REACHABILITY_SERVER = "http://google.com" // can be any URL you want

    private fun hasNetworkAvailable(context: Context): Boolean {
        val service = Context.CONNECTIVITY_SERVICE
        val manager = context.getSystemService(service) as ConnectivityManager?
        val network = manager?.activeNetworkInfo
        Log.d(classTag, "hasNetworkAvailable: ${(network != null)}")
        return (network != null)
    }

    fun hasInternetConnected(context: Context): Boolean {
        if (hasNetworkAvailable(context)) {
            try {
                val connection = URL(REACHABILITY_SERVER).openConnection() as HttpURLConnection
                connection.setRequestProperty("User-Agent", "Test")
                connection.setRequestProperty("Connection", "close")
                connection.connectTimeout = 1500
                connection.connect()
                Log.d(classTag, "hasInternetConnected: ${(connection.responseCode == 200)}")
                return (connection.responseCode == 200)
            } catch (e: IOException) {
                Log.e(classTag, "Error checking internet connection", e)
            }
        } else {
            Log.w(classTag, "No network available!")
        }
        Log.d(classTag, "hasInternetConnected: false")
        return false
    }
}

您甚至可以根据策略和限制将REACHABILITY_SERVER作为参数传递,例如,当您在中国时,您可以检查https://baidu.com而不是https://google.com。

调用示例中,

val webLoaderThread = Thread {
   if (MyReachability.hasInternetConnected(this)){
       runOnUiThread {
           //mWebView.loadUrl(LANDING_SERVER) // connected
       }
   } else {
       runOnUiThread {
           //showDialogNoNetwork() // not connected
       }
   }
}
webLoaderThread.start()

安卓系统权限

不要忘记将以下权限添加到你的AndroidManifest.xml中

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

其他回答

最简单的解决办法是

在大多数情况下,如果他/她想连接到远程服务器,只会检查互联网连接,所以简单和最好的解决方案是ping你的服务器,如下所示。

public boolean isConnected() {
    final String command = "ping -c 1 yourExmapleDomain.com";
    boolean isConnected = false;
    try {
        isConnected = Runtime.getRuntime().exec(command).waitFor() == 0;
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return isConnected;
}

这种方法为您提供了一个非常快速的方法(用于实时反馈)或较慢的方法(用于需要可靠性的一次性检查)。

public boolean isNetworkAvailable(bool SlowButMoreReliable) {
    bool Result = false; 
    try {
        if(SlowButMoreReliable){
            ConnectivityManager MyConnectivityManager = null;
            MyConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

            NetworkInfo MyNetworkInfo = null;
            MyNetworkInfo = MyConnectivityManager.getActiveNetworkInfo();

            Result = MyNetworkInfo != null && MyNetworkInfo.isConnected();

        } else
        {
            Runtime runtime = Runtime.getRuntime();
            Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");

            int i = ipProcess.waitFor();

            Result = i== 0;

        }

    } catch(Exception ex)
    {
        //Common.Exception(ex); //This method is one you should have that displays exceptions in your log
    }
    return Result;
}

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

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
public boolean isNetworkAvailable(Context context) {
    ConnectivityManager connectivityManager
            = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

以下是您需要的许可:

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

Kotlin和协程

我将函数放置在一个ViewModel中,该ViewModel具有viewModelScope。使用一个可观察的LiveData,我通知一个活动有关连接。

ViewModel

 fun checkInternetConnection(timeoutMs: Int) {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                val socket = Socket()
                val socketAddress = InetSocketAddress("8.8.8.8", 53)

                socket.connect(socketAddress, timeoutMs)
                socket.close()

                _connection.postValue(true)
            }
            catch(ex: IOException) {
                _connection.postValue(false)
            }
        }
    }
 private val _connection = MutableLiveData<Boolean>()
 val connection: LiveData<Boolean> = _connection

活动

 private fun checkInternetConnection() {
     viewModel.connection.observe(this) { hasInternet ->
         if(!hasInternet) {
             //hasn't connection
         }
         else {
            //has connection
         }
     }
  }