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

当前回答

对我来说,在Activity类中检查连接状态并不是一个好的实践,因为

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

应该在那里调用,或者您需要下推您的活动实例(上下文)到连接处理程序类,以能够检查那里的连接状态 当没有可用的连接(wifi,网络)时,我捕捉到UnknownHostException异常:

JSONObject jObj = null;
Boolean responded = false;
HttpGet requestForTest = new HttpGet("http://myserver.com");
try {
    new DefaultHttpClient().execute(requestForTest);
    responded = true;
} catch (UnknownHostException e) {
    jObj = new JSONObject();
    try {
        jObj.put("answer_code", 1);
        jObj.put("answer_text", "No available connection");
    } catch (Exception e1) {}
    return jObj;
} catch (IOException e) {
    e.printStackTrace();
}

通过这种方式,我可以处理这种情况连同其他情况在同一类(我的服务器总是响应回json字符串)

其他回答

有不止一种方法

第一,最短但效率低的方法

只需要网络状态权限

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

然后这个方法,

 public boolean activeNetwork () {
        ConnectivityManager cm =
                (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        boolean isConnected = activeNetwork != null &&
                activeNetwork.isConnected();

        return isConnected;

    }

正如在回答中所看到的ConnectivityManager是一个解决方案,我只是在一个方法中添加了它,这是一个简化的方法 ConnectivityManager返回true,如果有网络访问而不是互联网访问,这意味着如果你的WiFi连接到路由器,但路由器没有互联网,它返回true,它检查连接可用性

二、高效的方式

需要网络状态和Internet权限

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

然后这门课,

 public class CheckInternetAsyncTask extends AsyncTask<Void, Integer, Boolean> {

        private Context context;

        public CheckInternetAsyncTask(Context context) {
            this.context = context;
        }

        @Override
        protected Boolean doInBackground(Void... params) {

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

            assert cm != null;
            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            boolean isConnected = activeNetwork != null &&
                    activeNetwork.isConnected();


            if (isConnected) {
                try {
                    HttpURLConnection urlc = (HttpURLConnection)
                            (new URL("http://clients3.google.com/generate_204")
                                    .openConnection());
                    urlc.setRequestProperty("User-Agent", "Android");
                    urlc.setRequestProperty("Connection", "close");
                    urlc.setConnectTimeout(1500);
                    urlc.connect();
                    if (urlc.getResponseCode() == 204 &&
                            urlc.getContentLength() == 0)
                        return true;

                } catch (IOException e) {
                    Log.e("TAG", "Error checking internet connection", e);
                    return false;
                }
            } else {
                Log.d("TAG", "No network available!");
                return false;
            }


            return null;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            Log.d("TAG", "result" + result);

            if(result){
                // do ur code
            }

        }


    }

叫CheckInternetAsyncTask

new CheckInternetAsyncTask(getApplicationContext()).execute();

部分解释:-

you have to check Internet on AsyncTask, otherwise it can throw android.os.NetworkOnMainThreadException in some cases ConnectivityManager used to check the network access if true sends request (Ping) Request send to http://clients3.google.com/generate_204, This well-known URL is known to return an empty page with an HTTP status 204 this is faster and more efficient than http://www.google.com , read this. if you have website it's preferred to put you website instead of google, only if you use it within the app Timeout can be changed range (20ms -> 2000ms), 1500ms is commonly used

不要检查WIFI连接或移动数据连接,试着点击任何托管域。以便您可以检查WIFI/Mobile连接是否具有连接公共互联网的能力。

如果您的移动设备能够连接到所提供的公共域,则将返回以下内容。

boolean isReachable()
        {
            boolean connected = false;
            String instanceURL = "Your trusted domain name";
            Socket socket;
            try {
                socket = new Socket();
                SocketAddress socketAddress = new InetSocketAddress(instanceURL, 80);
                socket.connect(socketAddress, 5000);
                if (socket.isConnected()) {
                    connected = true;
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                socket = null;
            }
            return connected;
        }

希望对大家有所帮助。

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

由于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 }

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

正如Android文档建议的那样,之后

getActiveNetworkInfo()在Android 10中已弃用。使用 而不是针对Android 10 (API级别)的应用程序的NetworkCallbacks 29)更高。

下面是我们目前检查网络连接的方法:

val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
val isConnected: Boolean = activeNetwork?.isConnectedOrConnecting == true

使用NetworkCallbacks检查网络连接的新方法

步骤1:

    private lateinit var connectivityManager:ConnectivityManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    }

步骤2:创建回调:

private val callback = object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        Timber.e("Network:onAvailable")
    }

    override fun onLost(network: Network) {
        super.onLost(network)
        Timber.e("Network:onLost")
    }

}

步骤3:注册和取消注册回调:

private fun registerNetworkCallback() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        connectivityManager.registerDefaultNetworkCallback(callback)
    } else {
        // Old way to check network connection
    }
}

override fun onStop() {
    unRegisterNetworkCallback()
    super.onStop()
}

private fun unRegisterNetworkCallback() {
    connectivityManager.unregisterNetworkCallback(callback)
}

结帐更新详情如下链接:

https://developer.android.com/training/monitoring-device-state/connectivity-status-type

要让getActiveNetworkInfo()工作,您需要向清单中添加以下内容。

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