我得到了一个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文档建议的那样,之后
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
只需创建下面的类来检查internet连接:
public class ConnectionStatus {
private Context _context;
public ConnectionStatus(Context context) {
this._context = context;
}
public boolean isConnectionAvailable() {
ConnectivityManager connectivity = (ConnectivityManager) _context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null) {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null)
for (int i = 0; i < info.length; i++)
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
return false;
}
}
该类仅包含一个返回连接状态布尔值的方法。因此,简单来说,如果该方法找到一个到Internet的有效连接,则返回值为true,否则为false,如果没有找到有效连接。
MainActivity中的下面的方法调用前面描述的方法的结果,并提示用户进行相应的操作:
public void addListenerOnWifiButton() {
Button btnWifi = (Button)findViewById(R.id.btnWifi);
iia = new ConnectionStatus(getApplicationContext());
isConnected = iia.isConnectionAvailable();
if (!isConnected) {
btnWifi.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
Toast.makeText(getBaseContext(), "Please connect to a hotspot",
Toast.LENGTH_SHORT).show();
}
});
}
else {
btnWifi.setVisibility(4);
warning.setText("This app may use your mobile data to update events and get their details.");
}
}
在上面的代码中,如果结果为假,(因此没有互联网连接,用户将被带到Android wi-fi面板,在那里他将被提示连接到wi-fi热点。
我在这里看到了很多过时的答案,所以我决定加入我的答案。
由于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 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,一切正常,并且您的设备有互联网连接。