Volley é uma biblioteca de rede para Android desenvolvida pelo Google para execução eficiente de requisições HTTP e carregamento de imagens. A biblioteca gerencia automaticamente um pool de threads, armazena respostas em cache e prioriza requisições. De acordo com Google, 2025, o Volley continua sendo uma escolha popular para projetos que exigem um início rápido sem configurar dependências complexas.
Principais conclusões
Volley é uma biblioteca para comunicação de rede em aplicativos Android, apresentada pelo Google na conferência I/O 2013. O nome Volley significa “um disparo” — a biblioteca foi projetada para executar múltiplas requisições rápidas paralelas, características de aplicativos orientados à interface do usuário, onde a velocidade de resposta da interface é importante.
Volley foi criada como uma solução para os problemas do HttpURLConnection e AsyncTask: gerenciamento manual de threads, falta de cache, complexidade de priorização de requisições e código volumoso. O Google posicionou o Volley como uma biblioteca para operações do tipo “fire-and-forget” — pequenas requisições cujo resultado é exibido imediatamente na interface.
A arquitetura do Volley inclui três componentes principais: RequestQueue (gerenciador de fila), CacheDispatcher (thread para respostas em cache) e NetworkDispatcher (threads de rede). Essa arquitetura distribui automaticamente as requisições: primeiro o cache é verificado e, somente na sua ausência, uma requisição de rede é feita. Isso reduz a latência para dados repetidos em 50–80%.
RequestQueue é a classe central do Volley. Objetos Request<T> são adicionados a ela, e a fila os distribui automaticamente entre dois tipos de threads: CacheDispatcher (uma thread, lida com requisições com possível cache) e NetworkDispatcher (várias threads, realizam requisições HTTP reais). Por padrão, o Volley cria 4 threads de rede.
Ao adicionar uma requisição, a RequestQueue verifica se pode ser servida pelo cache. Se o cache contém uma resposta atualizada, o CacheDispatcher a retorna imediatamente, sem uma requisição de rede. Se o cache está desatualizado ou ausente, a requisição é passada para o NetworkDispatcher. A prioridade da requisição (low, normal, high, immediate) determina a ordem de processamento dentro da fila — requisições com prioridade high são processadas antes das normais.
Após a execução da requisição, o resultado é entregue à thread principal (UI thread) via Handler. O Volley alterna automaticamente os callbacks onResponse() e onErrorResponse() para a thread principal, para que a interface possa ser atualizada diretamente no callback sem alternância adicional de threads. Isso simplifica o código e elimina toda uma classe de erros de threading.
Outra característica do Volley é a desduplicação automática de requisições. Se duas requisições GET idênticas para a mesma URL com os mesmos parâmetros forem adicionadas à fila, o Volley executa apenas uma delas e retorna a mesma resposta para ambos os callbacks. Isso é especialmente útil para telas onde vários componentes solicitam independentemente os mesmos dados — por exemplo, um perfil de usuário que é necessário simultaneamente para o cabeçalho e um fragmento de configurações.
Cada requisição passa por uma sequência de etapas: criar uma Request, adicioná-la à RequestQueue, verificar o cache (CacheDispatcher), executar a requisição HTTP (NetworkDispatcher), analisar a resposta pelo Response.Listener, entregar o resultado à thread da UI. Quando uma requisição é cancelada (cancel), a RequestQueue a remove da fila e impede que os callbacks sejam invocados.
O Volley também suporta RetryPolicy, que determina o número de tentativas de repetição em falhas. O DefaultRetryPolicy por padrão faz uma tentativa de repetição com um tempo limite de 2,5 segundos. Para conexões instáveis, o número de repetições pode ser aumentado para 3 e o tempo limite para 10 segundos. Uma RetryPolicy personalizada é implementada através da interface RetryPolicy com os métodos getCurrentTimeout, getCurrentRetryCount e retry.
O Volley fornece tipos de requisição prontos para formatos de dados comuns. Cada tipo implementa a classe abstrata Request<T> e define um método para analisar a resposta. Para formatos personalizados, você pode criar seu próprio tipo sobrescrevendo o método parseNetworkResponse.
| Tipo de requisição | Tipo de retorno | Propósito |
|---|---|---|
| StringRequest | String | Obter uma resposta de texto bruta |
| JsonObjectRequest | JSONObject | Analisar um objeto JSON |
| JsonArrayRequest | JSONArray | Analisar um array JSON |
| ImageRequest | Bitmap | Carregar e decodificar uma imagem |
| ClearCacheRequest | — | Limpar o cache do Volley |
Para trabalhar com Gson ou Kotlinx Serialization, você pode criar uma Request<T> personalizada que use o analisador escolhido no parseNetworkResponse. Isso permite receber objetos tipados diretamente, evitando a análise manual do JSONObject. Essa abordagem é especialmente útil para projetos que já usam serialização via Gson ou Moshi.
Para enviar dados, o Volley suporta três tipos de corpo: JSONObject (via JsonObjectRequest com método POST), Form-encoded (via HashMap<String, String> no construtor) e Multipart (via um MultipartRequest personalizado). Requisições Multipart são úteis para upload de imagens e arquivos, mas exigem implementação manual, pois o Volley não possui suporte integrado para multipart/form-data, ao contrário do OkHttp ou Dio.
As limitações do Volley se tornam perceptíveis ao trabalhar com respostas grandes. O Volley carrega toda a resposta na memória antes de passá-la ao callback, o que pode causar OutOfMemoryError para arquivos JSON maiores que 10–20 MB. Para baixar arquivos grandes, o Volley não é adequado — use DownloadManager ou OkHttp com ResponseBody de streaming. O Volley também não suporta retomada de downloads interrompidos (cabeçalho Range) e não funciona com protocolos de streaming como Server-Sent Events ou WebSocket em tempo real.
Vejamos um exemplo básico — um StringRequest para buscar dados de um servidor. Primeiro, uma RequestQueue é criada via Volley.newRequestQueue(context). Em seguida, uma requisição é formada com uma URL e callbacks de sucesso e erro.
val queue = Volley.newRequestQueue(context)
val request = StringRequest(
Request.Method.GET,
"https://api.github.com/users/octocat",
{ response ->
println("Resposta: $response")
},
{ error ->
println("Erro: ${error.message}")
}
)
queue.add(request)
Para uma requisição JSON, é usado o JsonObjectRequest, que analisa automaticamente a resposta em um JSONObject. O Volley suporta requisições GET e POST. Para POST, um JSONObject é passado no corpo da requisição.
val jsonBody = JSONObject()
jsonBody.put("name", "New Repo")
jsonBody.put("description", "Created via Volley")
val request = JsonObjectRequest(
Request.Method.POST,
"https://api.github.com/user/repos",
jsonBody,
{ response ->
println("Criado: ${response.getString("id")}")
},
{ println("Erro: $it") }
)
queue.add(request)
Para cancelar uma requisição, usa-se o método cancel() ou o cancelamento em grupo por tag. Ao cancelar, o Volley não chama nem onResponse nem onErrorResponse, o que impede atualizações da interface após sair da tela. Isso é importante para prevenir vazamentos de memória em Activity e Fragment.
request.tag = "profile_request"
queue.add(request)
// Cancelamento ao sair da tela
queue.cancelAll("profile_request")
ImageLoader é uma classe wrapper sobre RequestQueue, otimizada para carregar imagens. Ele suporta cache em memória (LruCache) e cancela automaticamente as requisições quando ImageView é reutilizado em listas RecyclerView. O ImageLoader também dimensiona as imagens para caber no tamanho da View, economizando memória.
NetworkImageView é uma View personalizada que se integra ao ImageLoader e gerencia automaticamente o carregamento: exibe um placeholder durante o carregamento, substitui por um erro em caso de falha e cancela a requisição quando a View sai da tela. O DefaultImageUrlLoader carrega uma imagem por URL e a armazena em LruCache para reexibição rápida.
Para usar o ImageLoader, basta criar uma instância via ImageLoader(queue, ImageCache), onde ImageCache é uma implementação da interface ImageCache com LruCache interno. O NetworkImageView no layout XML é vinculado ao ImageLoader através do método setImageUrl(), e todo o carregamento ocorre completamente automático sem código adicional para lidar com placeholders e erros.
Criar uma RequestQueue em cada Activity é um erro comum que leva à duplicação de threads e confusão no cache. Recomenda-se criar a RequestQueue uma vez no Application ou através de uma classe singleton. Caso contrário, cada tela terá seu próprio pool de threads e o cache será armazenado separadamente para cada fila.
Ignorar o cancelamento de requisições ao girar a tela. Ao alterar a configuração, a Activity é recriada e os callbacks da Activity antiga continuam na memória. Isso causa vazamentos e tentativas de atualizar uma View destruída. Sempre cancele as requisições em onStop() através de cancelAll() com uma tag específica da Activity.
O Volley não suporta HTTP/2 e corrotinas — isso não é um erro de uso, mas uma limitação arquitetural. O Volley foi criado em 2013 e não suporta protocolos modernos e corrotinas do Kotlin. Para novos projetos, o Google recomenda usar Retrofit + OkHttp. O Volley é adequado apenas para suportar projetos legados ou aplicativos simples com requisitos mínimos de rede.
Perguntas frequentes
Volley está obsoleto para novos projetos — o Google não atualiza a biblioteca desde 2017. Para aplicativos modernos, use Retrofit + OkHttp ou Ktor Client. O Volley só pode ser usado para suportar código legado existente ou em projetos educacionais simples com tarefas mínimas de rede.
Falta de suporte para tecnologias modernas: HTTP/2, corrotinas do Kotlin, desenvolvimento multiplataforma e serialização tipada. O Volley usa JSONObject e JSONArray sem tipos, o que leva a erros em tempo de execução quando a estrutura JSON não corresponde às expectativas.
Através do ImageLoader e do NetworkImageView. O ImageLoader usa LruCache para cache de imagens em memória e cancela automaticamente as requisições quando as views são reutilizadas. O NetworkImageView mostra um placeholder durante o carregamento e o substitui pela imagem carregada ou um indicador de erro.
Tecnicamente sim — através de um wrapper suspendCoroutine { } sobre os callbacks do Volley. Mas isso não oferece vantagens, pois o Volley não suporta cancelamento baseado em cancelamento de corrotina e não trabalha diretamente com Dispatchers.IO. É melhor usar o Ktor Client com suporte nativo a corrotinas.
O timeout é configurado através do RetryPolicy. Por padrão, o DefaultRetryPolicy usa um timeout de 2,5 segundos e uma tentativa de repetição. Para alterar os parâmetros: request.retryPolicy = DefaultRetryPolicy(10000, 1, 1.0f) — 10 segundos de timeout, uma tentativa.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também