我得到了一个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字符串)
我在这里看到了很多过时的答案,所以我决定加入我的答案。
由于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 }
据我测试,无论应用程序是在后台还是前台,这都是可行的。
我已经经历了所有的答案,我想出了我自己的答案,首先检查互联网是否可用,如果互联网可用,然后检查它是否活跃。
我已经包括了所有必要的方法和类来检查活跃的Internet连接。
NetworkUtils.class
public class NetworkUtils {
public static final int STATUS_CONNECTED = 0 ;
public static boolean isInternetAvailable(Context ctx){
ConnectivityManager cm = (ConnectivityManager)ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
public static int isInternetActiveWithPing() {
try {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
int exitValue = process.waitFor();
return exitValue;
} catch (Exception ex) {
return -1;
}
}
public static boolean isInternetActiveWithInetAddress() {
try {
InetAddress inetAddress = InetAddress.getByName("www.google.com");
return inetAddress != null && !inetAddress.toString().equals("");
} catch (Exception ex) {
return false;
}
}
public static void displayInternetConnectionMessage(Context ctx){
Toast.makeText(ctx, "Check Internet Connection", Toast.LENGTH_SHORT).show();
}
}
你可以使用下面的代码检查互联网是否活跃:
private void checkInternetConnection() {
if (NetworkUtils.isInternetAvailable(this)) {
new Thread(new Runnable() {
@Override
public void run() {
if (NetworkUtils.isInternetActiveWithPing() == NetworkUtils.STATUS_CONNECTED) {
performNetworkingOperations();
} else {
if (NetworkUtils.isInternetActiveWithInetAddress()) {
performNetworkingOperations();
} else {
displayConnectionMessage();
}
}
}
}).start();
} else {
displayConnectionMessage();
}
}
private void performNetworkingOperations() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "Internet is Available", Toast.LENGTH_SHORT).show();
}
});
}
private void displayConnectionMessage() {
runOnUiThread(new Runnable() {
@Override
public void run() {
NetworkUtils.displayInternetConnectionMessage(MainActivity.this);
}
});
}