Представьте, что я нахожусь в службе, у которой уже есть фоновый поток. Могу ли я сделать запрос, используя залп в том же потоке, чтобы обратные вызовы происходили синхронно?
Для этого есть 2 причины: - Во-первых, мне не нужен еще один поток, и создание его было бы пустой тратой. - Во-вторых, если я нахожусь в ServiceIntent, выполнение потока завершится до обратного вызова, и поэтому у меня не будет ответа от Volley. Я знаю, что могу создать свою собственную Службу, у которой есть поток с циклом выполнения, который я могу контролировать, но было бы желательно иметь эту функциональность в режиме залпа.
Спасибо!
java
android
android-volley
LocoMike
источник
источник
Ответы:
Похоже, это возможно с
RequestFuture
классом Волли . Например, чтобы создать синхронный запрос JSON HTTP GET, вы можете сделать следующее:источник
JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorlistener)
конструктор.RequestFuture<JSONObject>
реализует какListener<JSONObject>
иErrorListener
интерфейсы, поэтому он может быть использован в качестве последних двух параметров.future.get()
тогда приложение остановится или запустится с тайм-аутом, если установлено так.Обратите внимание, что ответ @Matthews правильный, НО если вы находитесь в другом потоке и выполняете залп, когда у вас нет Интернета, ваш обратный вызов ошибки будет вызываться в основном потоке, но поток, в котором вы находитесь, будет заблокирован НАВСЕГДА. (Поэтому, если этот поток является IntentService, вы никогда не сможете отправить ему другое сообщение, и ваш сервис будет в основном мертвым).
Используйте версию
get()
с тайм-аутомfuture.get(30, TimeUnit.SECONDS)
и перехватите ошибку, чтобы выйти из потока.Чтобы соответствовать ответу @Mathews:
Ниже я завернул его в метод и использовал другой запрос:
источник
IntentService
- исполнитель пула потоков для одного потока, поэтому IntentService будет заблокирован до тех пор, пока он находится в цикле,Вероятно, рекомендуется использовать Futures, но если по какой-либо причине вы этого не хотите, вместо того, чтобы создавать свою собственную синхронизированную блокировку, вы должны использовать файл
java.util.concurrent.CountDownLatch
. Так что это будет работать такПоскольку люди, казалось, действительно пытались это сделать и столкнулись с некоторыми проблемами, я решил, что на самом деле предоставлю "реальный" рабочий образец этого в использовании. Вот это https://github.com/timolehto/SynchronousVolleySample
Теперь, хотя решение работает, у него есть некоторые ограничения. Самое главное, вы не можете вызвать его в основном потоке пользовательского интерфейса. Volley действительно выполняет запросы в фоновом режиме, но по умолчанию Volley использует основную
Looper
часть приложения для отправки ответов. Это вызывает взаимоблокировку, поскольку основной поток пользовательского интерфейса ожидает ответа, ноLooper
ожидаетonCreate
завершения перед обработкой доставки. Если вы действительно действительно хотите это сделать, вы можете вместо статических вспомогательных методов создать экземпляр своего собственного,RequestQueue
передавая его своим собственнымExecutorDelivery
привязанным кHandler
using a,Looper
который привязан к другому потоку из основного потока пользовательского интерфейса.источник
В качестве дополнительного наблюдения к ответам @Blundells и @Mathews я не уверен, что Volley доставит какой-либо вызов кому- либо, кроме основного потока.
Источник
Взглянув на
RequestQueue
реализацию, кажется, чтоRequestQueue
он использует aNetworkDispatcher
для выполнения запроса и aResponseDelivery
для доставки результата (ResponseDelivery
вводится вNetworkDispatcher
). ВResponseDelivery
свою очередь, создается с помощьюHandler
порождения из основного потока (где-то около строки 112 вRequestQueue
реализации).Где-то около строки 135 в
NetworkDispatcher
реализации кажется, что успешные результаты доставляются так же,ResponseDelivery
как и любые ошибки. Очередной раз; aResponseDelivery
основан наHandler
порождении из основного потока.обоснование
Для случая использования, когда запрос должен быть сделан из
IntentService
, справедливо предположить, что поток службы должен блокироваться до тех пор, пока мы не получим ответ от Volley (чтобы гарантировать живую область выполнения для обработки результата).Предлагаемые решения
Один из подходов будут переопределить путь по умолчанию
RequestQueue
создается , когда альтернативный конструктор используется вместо инжекции ,ResponseDelivery
который размножается от текущей нити , а не в главном потоке. Однако я не исследовал последствий этого.источник
finish()
метод вRequest
классе иRequestQueue
классе являются частными пакетами, кроме использования метода взлома отражений. Я не уверен, что есть способ обойти это. То, что я в конечном итоге сделал, чтобы предотвратить что-либо, работающее в основном потоке (UI), это настройка альтернативного потока Looper (использованиеLooper.prepareLooper(); Looper.loop()
) и передачаExecutorDelivery
экземпляраRequestQueue
конструктору с обработчиком для этого петлителя. У вас есть накладные расходы другого петлителя, но вы неЯ использую блокировку для достижения этого эффекта, теперь мне интересно, правильно ли это, по моему мнению, кто-то хочет прокомментировать?
источник
catch (InterruptedException e)
внутри цикла while. В противном случае поток не сможет ждать, если по какой-то причинеЯ хочу добавить кое-что к принятому ответу Мэтью. Хотя
RequestFuture
может показаться, что вы делаете синхронный вызов из созданного вами потока, это не так. Вместо этого вызов выполняется в фоновом потоке.Из того, что я понимаю после прохождения библиотеки, запросы в
RequestQueue
отправляются в ееstart()
методе:Теперь как
CacheDispatcher
иNetworkDispatcher
классы расширения потока. Таким образом, эффективно создается новый рабочий поток для удаления очереди запросов, а ответ возвращается в прослушиватели успеха и ошибок, реализованные внутриRequestFuture
.Хотя ваша вторая цель достигнута, но первая цель - нет, поскольку всегда создается новый поток, независимо от того, из какого потока вы выполняете
RequestFuture
.Короче говоря, истинный синхронный запрос невозможен с библиотекой Volley по умолчанию. Поправь меня, если я ошибаюсь.
источник
Вы можете выполнить запрос синхронизации с залпом, но вы должны вызвать метод в другом потоке, иначе ваше работающее приложение заблокируется, это должно быть так:
после этого вы можете вызвать метод в потоке:
источник