Imagine que eu esteja em um Serviço que já tenha um encadeamento em segundo plano. Posso fazer uma solicitação usando vôlei no mesmo thread, para que os retornos de chamada ocorram de forma síncrona?
Existem duas razões para isso: - Primeiro, não preciso de outro thread e seria um desperdício criá-lo. - Segundo, se eu estiver em um ServiceIntent, a execução do encadeamento será concluída antes do retorno de chamada e, portanto, não terei resposta da Volley. Eu sei que posso criar meu próprio serviço que tem algum segmento com um runloop que posso controlar, mas seria desejável ter essa funcionalidade no voleio.
Obrigado!
java
android
android-volley
LocoMike
fonte
fonte
Respostas:
Parece que é possível com a
RequestFuture
aula de Volley . Por exemplo, para criar uma solicitação JSON HTTP GET síncrona, você pode fazer o seguinte:fonte
JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorlistener)
construtor.RequestFuture<JSONObject>
implementa as interfacesListener<JSONObject>
eErrorListener
, para que possa ser usado como os dois últimos parâmetros.future.get()
aplicativo, o aplicativo será interrompido ou atingirá o tempo limite, com certeza, se definido.Nota A resposta do @Matthews está correta, MAS se você estiver em outro segmento e fizer uma chamada de vôlei quando não tiver Internet, seu retorno de erro será chamado no segmento principal, mas o segmento em que você estiver será bloqueado PARA SEMPRE. (Portanto, se esse segmento for um IntentService, você nunca poderá enviar outra mensagem para ele e seu serviço estará basicamente morto).
Use a versão
get()
que tem um tempo limitefuture.get(30, TimeUnit.SECONDS)
e pegue o erro para sair do seu encadeamento.Para corresponder à resposta de @Mathews:
Abaixo, envolvi-o em um método e use uma solicitação diferente:
fonte
IntentService
é um executor pool de threads de um único segmento, portanto, que IntentService será bloqueado foreveras ele fica em um loopProvavelmente, é recomendável usar o Futuro, mas se por qualquer motivo você não quiser, em vez de preparar sua própria coisa de bloqueio sincronizado, use a
java.util.concurrent.CountDownLatch
. Então isso funcionaria assim ..Como as pessoas pareciam realmente tentar fazer isso e tiveram alguns problemas, decidi que eu realmente forneceria uma amostra da "vida real" disso em uso. Aqui está https://github.com/timolehto/SynchronousVolleySample
Agora, embora a solução funcione, ela tem algumas limitações. Mais importante, você não pode chamá-lo no thread principal da interface do usuário. O Volley executa as solicitações em segundo plano, mas, por padrão, o Volley usa o principal
Looper
do aplicativo para despachar as respostas. Isso causa um impasse, pois o thread principal da interface do usuário está aguardando a resposta, masLooper
está aguardandoonCreate
a conclusão antes de processar a entrega. Se você realmente quiser fazer isso, poderá, em vez dos métodos auxiliares estáticos, instanciar o seu próprioRequestQueue
passando-oExecutorDelivery
vinculado a umHandler
uso de umLooper
que está vinculado a um thread diferente do thread principal da interface do usuário.fonte
Como uma observação complementar para as respostas @Blundells e @Mathews, não tenho certeza de que nenhuma ligação seja entregue a nada além do segmento principal de Volley.
A fonte
Observando a
RequestQueue
implementação , parece que vocêRequestQueue
está usando aNetworkDispatcher
para executar a solicitação e aResponseDelivery
para entregar o resultado (o queResponseDelivery
é injetado noNetworkDispatcher
). PorResponseDelivery
sua vez, ele é criado com umHandler
spawn a partir do encadeamento principal (algo em torno da linha 112 naRequestQueue
implementação).Em algum lugar da linha 135 na
NetworkDispatcher
implementação , parece que também resultados bem-sucedidos são entregues da mesma maneiraResponseDelivery
que qualquer erro. Novamente; umResponseDelivery
baseado em umaHandler
semente do segmento principal.Fundamentação
Para o caso de uso em que uma solicitação deve ser feita
IntentService
, é justo supor que o encadeamento do serviço deve bloquear até recebermos uma resposta do Volley (para garantir um escopo de tempo de execução de vida para lidar com o resultado).Soluções sugeridas
Uma abordagem seria substituir a maneira padrão como a
RequestQueue
é criada , onde um construtor alternativo é usado, injetando umaResponseDelivery
que gera do encadeamento atual e não do encadeamento principal. Eu não investiguei as implicações disso, no entanto.fonte
finish()
método naRequest
classe e naRequestQueue
classe serem pacotes privados, além de usar um hack de reflexão, não tenho certeza de que haja uma maneira de contornar isso. O que acabei fazendo para impedir que qualquer coisa em execução no thread principal (UI) foi configurar um thread Looper alternativo (usandoLooper.prepareLooper(); Looper.loop()
) e transmitir umaExecutorDelivery
instância aoRequestQueue
construtor com um manipulador para esse looper. Você tem a sobrecarga de outro looper, mas ficar fora do segmento principalEu uso um bloqueio para alcançar esse efeito agora estou me perguntando se está correto meu caminho alguém quer comentar?
fonte
catch (InterruptedException e)
interior do loop while. Caso contrário fio vai deixar de esperar se interrompida por algum motivoQuero acrescentar algo à resposta aceita de Matthew. Embora
RequestFuture
possa parecer fazer uma chamada síncrona a partir do encadeamento que você a criou, ela não faz. Em vez disso, a chamada é executada em um encadeamento em segundo plano.Pelo que entendi depois de percorrer a biblioteca, os pedidos no
RequestQueue
são despachados em seustart()
método:Agora as classes
CacheDispatcher
eNetworkDispatcher
estendem o thread. Com tanta eficiência, um novo encadeamento de trabalho é gerado para desenfileirar a fila de solicitações e a resposta é retornada aos ouvintes de sucesso e erro implementados internamente porRequestFuture
.Embora seu segundo objetivo seja atingido, mas você não é o primeiro, uma vez que sempre é gerado um novo encadeamento, não importa de qual segmento você executa
RequestFuture
.Em resumo, a solicitação síncrona verdadeira não é possível com a biblioteca Volley padrão. Corrija-me se eu estiver errada.
fonte
Você pode fazer uma solicitação de sincronização com o voleio, mas deve chamar o método em um segmento diferente ou o aplicativo em execução bloqueará, deve ser assim:
Depois disso, você pode chamar o método no thread:
fonte