Android: проблемы с подключением в фоновом потоке после тревоги, когда «всегда включен» отключен - PullRequest
3 голосов
/ 09 мая 2011

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

В приложении для Android возникают проблемы с подключением при удаленном HTTP ("опрос") вызов от AsyncTask, который был запущен после того, как сработала сигнализация.

Поиск работает очень хорошо, когда стандартная настройка Android "Включить всегда включен мобильные данные " (Настройки -> Беспроводные сети -> Мобильные сети) включен до «вкл» .

Решение, которое работает: тревога исчезает, Android «Сервис» получает сигнал тревоги, запускает фоновый поток (AsyncTask). Новый поток приобретает частичное след блокировка, устанавливает соединение (опрос), уведомляет пользователя и освобождает звонок для пробуждения.

Пока все хорошо. Проблема в том, что когда всегда включен выключен "выключен" , опрос в большинстве случаев завершается неудачно, если телефон находился в режиме ожидания некоторое время (> 30 минут).

Поскольку поток опроса отправляет уведомление, я напрямую получаю отзыв о неудачная попытка опроса.

Мотивация:

Многие пользователи включают режим «всегда включен», чтобы уменьшить разрядку аккумулятора. Так что, скорее всего, что пользователи приложения сталкиваются с проблемами. Я хочу устранить или предотвратить «ошибки», с которыми столкнутся пользователи.

Попытки решения:

Я много экспериментировал без каких-либо серьезных прорывов:

  • несколько повторных попыток и промежуточных снов, чтобы дать телефону некоторое время для установления соединения
  • http-параметры (время ожидания и т. Д.)
  • другой HttpClient (Apache)

Вопросы:

  • Что именно точно означает настройку «всегда включен» и что должны учитывать разработчики?
  • Мне интересно, возможно ли обычно реализовать механизм опроса на основе аварийных сигналов , который может устанавливать соединение для передачи данных, даже если "всегда включен" выключен.
  • Существуют ли альтернативные решения (C2DM невозможен)?

Обновление:

Кажется, что не все устройства Android имеют настройку "всегда включен". Похоже, это устройство или, что более вероятно, зависит от поставщика.

Ответы [ 2 ]

0 голосов
/ 12 мая 2011

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

Интересно, пытаетесь ли вы установить соединение слишком быстро после пробуждения телефона, прежде чем он сможет защитить соединение.

Рассмотрим:

Проверка соединения в приемнике AlarmManager. Если соединения нет, то:

Прежде чем вернуться из приемника AlarmManager, запустите отдельный поток. В теме:

  1. Получить замок от пробуждения
  2. Регистрация приемника вещания для CONNECTIVITY_CHANGE
  3. Ожидайте достаточное количество времени для успешного соединения (на что указывает событие приемника вещания).
  4. Если время истечет, снимите блокировку пробуждения и остановите нить, и телефон снова перейдет в спящий режим.

Попробуйте установить соединение только после получения события от широковещательного приемника CONNECTIVITY_CHANGE.

0 голосов
/ 10 мая 2011

Если вы намереваетесь внедрить протокол прямой связи и пытаетесь сделать это с помощью кратковременного опроса, это может осветить проблему аналогичным образом:

У нас было похожее требование к нашему приложению, и мы заметили несколько вещей:

  1. Не в каждой сети даже есть предпочтение «Включить всегда мобильные данные». Я нахожусь на Verizon с DroidX, и эта опция отсутствует в меню. Данные всегда включены.

  2. Вопреки тому, что вы думаете, розетки НЕ убиваются, когда телефон переходит в спящее состояние, даже если вы не удерживаете частичную пробужденную блокировку. Ваше приложение прекращает получать широковещательные события, когда телефон переходит в спящий режим (например, события изменения подключения), поэтому вы не можете полагаться на ОС Android, которая сообщит вам, когда вы временно отключили соединение для передачи данных. Вместо того, чтобы выполнять опрос по тревоге, рассмотрите возможность длительного опроса, при котором вы отправляете HTTP-запрос с Keep-Alive, и держите соединение открытым до бесконечности, пока не получите ответ.

  3. Блокирующие операции чтения сокета не будут вызывать IOException, EOFException или иное, когда вы отбрасываете свой сигнал, поэтому вам необходимо периодически проверять состояние сети отдельным потоком. Самый простой способ сделать это - использовать класс NetworkInterface и создать что-то вроде этого:

.

private OnCheckNetworkConnectivity networkConnectivityCallback = new OnCheckNetworkConnectivity() {
        String ipAddress;

        public boolean isConnected() {
            String newIpAddress = getLocalIpAddress();
            if(newIpAddress != null) {
            if(ipAddress == null) {
                ipAddress = newIpAddress;
                return true;
            }
            if(!newIpAddress.equals(ipAddress)) {
                ipAddress = newIpAddress;
                return false;
            }

            // still the same IP address, we should still have the same connection
            return true;
            }

            ipAddress = null;
            return false;
        }

        public String getLocalIpAddress() {
            try {
                for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                    NetworkInterface intf = en.nextElement();
                    for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                        InetAddress inetAddress = enumIpAddr.nextElement();
                        if (!inetAddress.isLoopbackAddress()) {
                            return inetAddress.getHostAddress();
                        }
                    }
                }
            } catch (SocketException ex) {
            return null;
            }
            return null;
        }
    };
...