Как проверить доступ к интернету на Android? InetAddress никогда не выдает таймаут
Описание проблемы:
Я написал класс 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();
}
}
Проблема, с которой я сталкиваюсь, заключается в том, что даже если хост недоступен, метод isReachable(30)
по каким-то причинам не завершает выполнение в течение 30 секунд. Может быть, кто-то знает, как решить эту проблему или хотя бы может указать на возможные причины?
5 ответ(ов)
Нет необходимости усложнять. Самый простой и удобный способ – использовать разрешение ACCESS_NETWORK_STATE
и реализовать метод проверки подключения. Вот пример:
public boolean isOnline() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null &&
cm.getActiveNetworkInfo().isConnectedOrConnecting();
}
Также вы можете использовать метод requestRouteToHost
, если у вас есть конкретный хост и тип подключения (Wi-Fi / мобильная сеть), которые вас интересуют.
Не забудьте добавить в ваш Android манифест следующую строку:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Чтобы getActiveNetworkInfo()
работал, необходимо добавить следующее в файл манифеста:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Не забудьте разместить это разрешение внутри тега <manifest>
.
Посмотрите на класс ConnectivityManager. Вы можете использовать этот класс для получения информации о активных соединениях на устройстве. Документация доступна по ссылке: ConnectivityManager.
EDIT: Вы можете использовать следующий код, чтобы получить информацию о мобильном или Wi-Fi соединении:
Context.getSystemService(Context.CONNECTIVITY_SERVICE)
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
или
Context.getSystemService(Context.CONNECTIVITY_SERVICE)
.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
После этого можно проанализировать перечисление DetailedState объекта NetworkInfo.
EDIT EDIT: Чтобы проверить, есть ли доступ к определенному хосту, вы можете использовать метод:
Context.getSystemService(Context.CONNECTIVITY_SERVICE)
.requestRouteToHost(TYPE_WIFI, int hostAddress)
Очевидно, что я использую Context.getSystemService(Context.CONNECTIVITY_SERVICE)
в качестве прокси для вызова методов класса ConnectivityManager
, что можно записать так:
ConnectivityManager cm = (ConnectivityManager) Context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.yourMethodCallHere();
Ваш код выглядит хорошо и должен работать для проверки доступности сети. Он создает новый поток для выполнения запроса к Google и использует Handler
для обработки результата. Вот краткий обзор того, как это работает:
Проверка доступности сети: Метод
isNetworkAvailable
создает новый поток, в котором выполняется запрос к "http://m.google.com". Это делается в отдельном потоке для избежания блокировки основного потока, что важно в Android.Асинхронный запрос: Вы создаете еще один вложенный поток для выполнения HTTP-запроса. Если соединение удачно, переменная
responded
устанавливается вtrue
.Ожидание ответа: После отправки запроса основной поток засыпает на 100 миллисекунд и проверяет, был ли получен ответ. Если нет, он продолжает ждать до тех пор, пока не истечет заданный тайм-аут.
Отправка сообщения: После завершения ожидания, в зависимости от значения переменной
responded
, черезHandler
отправляется соответствующее сообщение: 0 (не подключено) или 1 (подключено).
Вот пример определения Handler
и его использования:
Handler h = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what != 1) { // код в случае отсутствия подключения
// действия при отсутствии соединения
} else { // код в случае подключения
// действия при наличии соединения
}
}
};
// Запуск теста
isNetworkAvailable(h, 2000); // получаем ответ в течение 2000 мс
Если у вас возникают проблемы или ошибки, возможно, стоит проверить наличие необходимых разрешений на интернет-соединение в вашем AndroidManifest.xml и убедиться, что ваше устройство подключено к интернету.
Ваш код выглядит достаточно просто и удобно для проверки наличия интернет-соединения. Он возвращает true
, если устройство подключено к сети и может получить доступ к странице с кодом состояния 200
. Не забывайте добавлять необходимые разрешения в файл AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Вот ваш метод isOnline()
с выделением основных шагов:
public boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
try {
URL url = new URL("http://www.google.com");
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
urlc.setConnectTimeout(3000); // Устанавливаем таймаут
urlc.connect();
if (urlc.getResponseCode() == 200) { // Проверка кода ответа
return true; // Если подключение успешно
}
} catch (MalformedURLException e) {
e.printStackTrace(); // Отладка на случай ошибки
} catch (IOException e) {
e.printStackTrace(); // Отладка на случай ошибки
}
}
return false; // Если нет подключения или ошибка
}
Обратите внимание на обработку исключений, это поможет выявить проблемы в случае неудачи. Также имейте в виду, что выполнение сетевых операций в основном потоке может привести к ошибкам, поэтому, если вы интегрируете этот метод в реальном приложении, стоит учитывать использование AsyncTask
или других средств асинхронного выполнения.
Как исправить 'android.os.NetworkOnMainThreadException'?
Загрузка файла на Android с отображением прогресса в ProgressDialog
Ошибка «Необходимо переопределить метод суперкласса» после импорта проекта в Eclipse
Почему в RecyclerView отсутствует onItemClickListener()?
Не удается запустить Eclipse - Java был запущен, но вернул код завершения = 13