Почему доступ к сети в моем широковещательном приемнике геозоны ненадежен?

Случай использования:

Когда срабатывает геозона, нам нужно связаться с сервером как можно скорее. Мы решили эту проблему с помощью неявного BroadcastReceiver, вызывающего службу в течение нескольких лет, но проблематичного в новых версиях из-за фоновых ограничений Doze и Oreo.

Попытки исправления:

  1. Мы переместили регистрацию геозоны с неявного на явный широковещательный приемник, чтобы обойти ограничение «фонового режима».

  2. Мы попытались сделать это, как в примерах Google, т. е. широковещательный приемник вызывает enqueueWork() для JobIntentService. Проблема в том, что мы часто замечали большую «задержку» между тем, когда задание было запланировано, и тем, когда оно фактически выполнялось. Наш рекорд больше часа!

Поэтому вместо этого мы попытались перенести все функции в BroadcastReceiver и использовать goAsync() для выполнения сетевого вызова. (если вы попытаетесь выполнить сетевую операцию синхронно, вы получите исключение «нет сети из основного потока»).

Это работает, поскольку мы можем запустить поток, и он выполняет код, но сетевая операция доставляет нам проблемы.


Проблема:

Таким образом, наше текущее решение из-за вышеуказанных проблем — это явный BroadcastReceiver, использующий goAsync() для вызова сервера.

Однако сетевой вызов работает с перебоями. Мы довольно часто получаем ошибки "java.net.SocketException: Socket isclosed". Это не проблема сервера, и она всегда работает при вызове из нашего "обычного" кода приложения.

Я не уверен, почему это происходит, но я подозреваю режим Doze? Хотя я не уверен, как я могу получить это, когда приемник фактически вызывается триггером геозоны.

Вопросы:

  1. Кто-нибудь знает, почему сетевая операция не удалась из нашего goAsync()? Опять же, многопоточность работает, просто мы получаем ошибки сокета при фактической сетевой операции.

  2. Есть ли в более новых версиях Android какой-либо способ от триггера геозоны сделать сетевой вызов напрямую, как мы пытаемся сделать, помимо того, что мы уже пробовали?

Указатели и мысли очень ценятся!


person Mathias    schedule 10.09.2018    source источник
comment
Лаг — это определенно Doze. Вы вообще используете BroadcastReceiver? Что касается Android O, это не требуется и не желательно. Попросите JobScheduler напрямую запланировать JobIntentService. Поскольку onHandleWork происходит в потоке, вы можете работать в сети там.   -  person Gabe Sechan    schedule 10.09.2018
comment
Если вы посмотрите на пример Google geofence на GitHub, они используют BroadcastReceiver, который вызывает jobintentservice. Выше я упоминал, почему я стараюсь избегать службы jobintent, между расписанием и выполнением проходит слишком много времени. github.com/googlesamples/android-play-location/tree/master/   -  person Mathias    schedule 10.09.2018
comment
Нет никакой причины использовать приемник вообще. Удалив его, такой проблемы не будет.   -  person Gabe Sechan    schedule 10.09.2018
comment
@Mathias Я не пробовал это, но мне интересно, если с помощью SyncAdapter в этом случае будет работать вместо goAsync. Я не верю, что на SyncAdapters в настоящее время распространяются фоновые ограничения Android O и P.   -  person Michael Krause    schedule 11.09.2018
comment
@ Майкл, хорошо, но мне все равно придется вызывать его из широковещательного приемника, а это значит, что мне все равно придется планировать его? Или вы имеете в виду, что я могу вызвать его по-старому? Стоит попробовать, я думаю   -  person Mathias    schedule 11.09.2018
comment
Вы пытались проверить PowerManager.isDeviceIdleMode(), чтобы увидеть, активен ли Doze? У меня нет ответа для вас, но мне тоже любопытно узнать.   -  person black    schedule 20.09.2018
comment
@Mathias Одна вещь, которая, как мне кажется, может усугубить эту проблему, заключается в том, что когда происходит переход геозоны, это может сопровождаться переходом сети от Wi-Fi->LTE или LTE->Wifi. Таким образом, вполне возможно, что вы не сможете сообщить о переходе сразу, и в этом случае вам придется запланировать повторную попытку, когда сеть снова станет доступной. Боюсь, когда дело доходит до геозоны на Android, приходится иметь дело с множеством угловых случаев.   -  person Michael Krause    schedule 20.09.2018
comment
@Mathias Просто передаю кое-что, что я узнал о попытке сообщить о переходе забора, когда приложение работает на Android P и находится в корзине RARE. Сегмент RARE ограничивает сетевую активность окном каждые 24 часа. Чтобы выйти из корзины RARE и сообщить о переходе по сети, вам нужно запустить службу переднего плана. В моем случае я сделал IntentService и запускаю его нормально, если я на Android ‹= N и запускаю на переднем плане на Android ›= O.   -  person Michael Krause    schedule 28.09.2018
comment
@Майкл. Спасибо за отзыв, мы тоже так сделали. Единственный способ заставить его выполняться в разумные сроки - через службу переднего плана + уведомление...   -  person Mathias    schedule 15.10.2018
comment
@Mathias Для меня работает служба переднего плана + метод уведомления. Не идеально, потому что уведомление показывается меньше секунды, но, по крайней мере, оно работает. Вы когда-нибудь находили лучшее решение или это все еще путь?   -  person Thomas Vos    schedule 20.09.2020
comment
@ Томас, да, мы делаем перетасовку на переднем плане ... К сожалению, я не знаю ничего лучше.   -  person Mathias    schedule 21.09.2020