Imagine que estoy en un servicio que ya tiene un hilo de fondo. ¿Puedo hacer una solicitud usando volley en ese mismo hilo, para que las devoluciones de llamada se realicen sincrónicamente?
Hay 2 razones para esto: - Primero, no necesito otro hilo y sería un desperdicio crearlo. - Segundo, si estoy en un ServiceIntent, la ejecución del subproceso finalizará antes de la devolución de llamada y, por lo tanto, no tendré respuesta de Volley. Sé que puedo crear mi propio servicio que tiene algún hilo con un runloop que puedo controlar, pero sería deseable tener esta funcionalidad en volea.
¡Gracias!
java
android
android-volley
LocoMike
fuente
fuente
Respuestas:
Parece que es posible con la
RequestFuture
clase de Volley . Por ejemplo, para crear una solicitud JSON HTTP GET síncrona, puede hacer lo siguiente:fuente
JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorlistener)
constructor.RequestFuture<JSONObject>
implementa las interfacesListener<JSONObject>
yErrorListener
, por lo que puede usarse como los dos últimos parámetros.future.get()
aplicación, entonces la aplicación se detendrá o se quedará sin tiempo de espera si está configurada.Tenga en cuenta que la respuesta de @Matthews es correcta PERO si está en otro subproceso y realiza una llamada de volea cuando no tiene Internet, su devolución de llamada de error se llamará en el subproceso principal, pero el subproceso en el que se encuentre se bloqueará PARA SIEMPRE. (Por lo tanto, si ese hilo es un IntentService, nunca podrá enviarle otro mensaje y su servicio estará básicamente muerto).
Utilice la versión de
get()
que tiene un tiempo de esperafuture.get(30, TimeUnit.SECONDS)
y detecte el error para salir de su hilo.Para coincidir con la respuesta de @Mathews:
A continuación lo envolví en un método y uso una solicitud diferente:
fuente
IntentService
es un ejecutor de grupo de subprocesos de un solo subproceso, por lo tanto, IntentService se bloqueará antes de que se asiente en un bucleProbablemente se recomienda usar los Futuros, pero si por alguna razón no desea hacerlo, en lugar de cocinar su propio bloqueo sincronizado, debe usar a
java.util.concurrent.CountDownLatch
. Entonces eso funcionaría así ...Como la gente parecía tratar de hacer esto y se encontró con algunos problemas, decidí que en realidad proporcionaría una muestra de trabajo de la "vida real" de esto en uso. Aquí está https://github.com/timolehto/SynchronousVolleySample
Ahora, aunque la solución funciona, tiene algunas limitaciones. Lo más importante, no puede llamarlo en el hilo principal de la interfaz de usuario. Volley ejecuta las solicitudes en segundo plano, pero de forma predeterminada, Volley utiliza
Looper
la aplicación principal para enviar las respuestas. Esto provoca un punto muerto ya que el subproceso principal de la interfaz de usuario está esperando la respuesta, peroLooper
está esperandoonCreate
que termine antes de procesar la entrega. Si realmente desea hacer esto, podría, en lugar de los métodos auxiliares estáticos, crear una instancia de su propiaRequestQueue
transmisión y pasarlaExecutorDelivery
a unHandler
usoLooper
que esté vinculado a un hilo diferente del hilo principal de la interfaz de usuario.fuente
Como observación complementaria a ambos @Blundells y @Mathews respuestas, no estoy seguro de cualquier llamada se entrega a cualquier cosa , pero el hilo principal mediante voleo.
La fuente
Al echar un vistazo a la
RequestQueue
implementación , parece queRequestQueue
está utilizando aNetworkDispatcher
para ejecutar la solicitud y aResponseDelivery
para entregar el resultado (ResponseDelivery
se inyecta en elNetworkDispatcher
). AResponseDelivery
su vez, se crea con unHandler
engendro del hilo principal (en algún lugar alrededor de la línea 112 en laRequestQueue
implementación).En algún lugar sobre la línea 135 en la
NetworkDispatcher
implementación , parece que también se entregan resultados exitosos a través de lo mismoResponseDelivery
que cualquier error. De nuevo; unaResponseDelivery
basada en unaHandler
freza desde el hilo principal.Razón fundamental
Para el caso de uso en el que se debe realizar una solicitud, es
IntentService
justo asumir que el hilo del servicio debe bloquearse hasta que tengamos una respuesta de Volley (para garantizar un alcance de tiempo de ejecución vivo para manejar el resultado).Las soluciones sugeridas
Un enfoque sería anular la forma predeterminada en que
RequestQueue
se crea a , donde se utiliza un constructor alternativo, inyectando unoResponseDelivery
que se genera a partir del hilo actual en lugar del hilo principal. Sin embargo, no he investigado las implicaciones de esto.fuente
finish()
método en laRequest
clase y laRequestQueue
clase son paquetes privados, además de usar un truco de reflexión, no estoy seguro de que haya una forma de evitarlo. Lo que terminé haciendo para evitar que algo se ejecute en el hilo principal (UI) fue configurar un hilo Looper alternativo (usandoLooper.prepareLooper(); Looper.loop()
) y pasar unaExecutorDelivery
instancia alRequestQueue
constructor con un controlador para ese looper. Tienes los gastos generales de otro looper pero mantente alejado del hilo principalUtilizo un candado para lograr ese efecto. Ahora me pregunto si es correcto para mí ¿alguien quiere comentar?
fuente
catch (InterruptedException e)
interior del bucle while. De lo contrario se producirá un error de rosca que esperar si se interrumpe por alguna razónQuiero agregar algo a la respuesta aceptada de Matthew. Si bien
RequestFuture
puede parecer que realiza una llamada sincrónica desde el subproceso que lo creó, no lo hace. En cambio, la llamada se ejecuta en un hilo de fondo.Por lo que entiendo después de pasar por la biblioteca, las solicitudes en el
RequestQueue
se envían en sustart()
método:Ahora ambos
CacheDispatcher
yNetworkDispatcher
clases extienden hilo. De manera efectiva, se genera un nuevo subproceso de trabajo para eliminar la cola de solicitudes y la respuesta se devuelve a los escuchas de éxito y error implementados internamente porRequestFuture
.Aunque se alcanza su segundo propósito, pero su primer propósito no lo es, ya que siempre se genera un nuevo hilo, sin importar desde qué hilo ejecute
RequestFuture
.En resumen, la solicitud síncrona verdadera no es posible con la biblioteca Volley predeterminada. Corrígeme si estoy equivocado.
fuente
Puede hacer una solicitud de sincronización con volley pero debe llamar al método en un hilo diferente o su aplicación en ejecución se bloqueará, debería ser así:
después de eso puedes llamar al método en hilo:
fuente