7

Как проверить доступ к интернету на Android? InetAddress никогда не выдает таймаут

1

Описание проблемы:

Я написал класс 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 ответ(ов)

2

Нет необходимости усложнять. Самый простой и удобный способ – использовать разрешение 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" />
0

Чтобы getActiveNetworkInfo() работал, необходимо добавить следующее в файл манифеста:

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

Не забудьте разместить это разрешение внутри тега <manifest>.

0

Посмотрите на класс 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();
0

Ваш код выглядит хорошо и должен работать для проверки доступности сети. Он создает новый поток для выполнения запроса к Google и использует Handler для обработки результата. Вот краткий обзор того, как это работает:

  1. Проверка доступности сети: Метод isNetworkAvailable создает новый поток, в котором выполняется запрос к "http://m.google.com". Это делается в отдельном потоке для избежания блокировки основного потока, что важно в Android.

  2. Асинхронный запрос: Вы создаете еще один вложенный поток для выполнения HTTP-запроса. Если соединение удачно, переменная responded устанавливается в true.

  3. Ожидание ответа: После отправки запроса основной поток засыпает на 100 миллисекунд и проверяет, был ли получен ответ. Если нет, он продолжает ждать до тех пор, пока не истечет заданный тайм-аут.

  4. Отправка сообщения: После завершения ожидания, в зависимости от значения переменной 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 и убедиться, что ваше устройство подключено к интернету.

0

Ваш код выглядит достаточно просто и удобно для проверки наличия интернет-соединения. Он возвращает 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 или других средств асинхронного выполнения.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь