Volley es una biblioteca de red para Android desarrollada por Google para la ejecución eficiente de solicitudes HTTP y carga de imágenes. La biblioteca gestiona automáticamente un grupo de hilos, almacena en caché las respuestas y prioriza las solicitudes. Según Google, 2025, Volley sigue siendo una opción popular para proyectos que requieren un inicio rápido sin configurar dependencias complejas.
Puntos clave
Volley es una biblioteca para la comunicación en red en aplicaciones Android, presentada por Google en la conferencia I/O 2013. El nombre Volley significa “una descarga” — la biblioteca está diseñada para ejecutar múltiples solicitudes rápidas en paralelo, características de las aplicaciones orientadas a la interfaz de usuario donde la velocidad de respuesta es importante.
Volley fue creada como una solución a los problemas de HttpURLConnection y AsyncTask: gestión manual de hilos, falta de caché, complejidad de priorización de solicitudes y código voluminoso. Google posicionó Volley como una biblioteca para operaciones “tipo fire-and-forget” — solicitudes pequeñas cuyo resultado se muestra inmediatamente en la interfaz.
La arquitectura de Volley incluye tres componentes principales: RequestQueue (gestor de cola), CacheDispatcher (hilo para respuestas cacheadas) y NetworkDispatcher (hilos de red). Esta arquitectura distribuye automáticamente las solicitudes: primero se verifica la caché, y solo si está ausente se realiza una solicitud de red. Esto reduce la latencia para datos repetidos en un 50–80%.
RequestQueue es la clase central de Volley. Se le añaden objetos Request<T> y la cola los distribuye automáticamente entre dos tipos de hilos: CacheDispatcher (un hilo, maneja solicitudes con posible caché) y NetworkDispatcher (varios hilos, realizan solicitudes HTTP reales). Por defecto, Volley crea 4 hilos de red.
Al añadir una solicitud, RequestQueue verifica si puede servirse desde la caché. Si la caché contiene una respuesta actualizada, CacheDispatcher la devuelve inmediatamente, sin una solicitud de red. Si la caché está desactualizada o ausente, la solicitud se pasa a NetworkDispatcher. La prioridad de la solicitud (low, normal, high, immediate) determina el orden de procesamiento dentro de la cola — las solicitudes con prioridad high se procesan antes que las normales.
Después de ejecutar la solicitud, el resultado se entrega al hilo principal (UI thread) a través de Handler. Volley cambia automáticamente los callbacks onResponse() y onErrorResponse() al hilo principal, por lo que la interfaz se puede actualizar directamente en el callback sin cambios de hilo adicionales. Esto simplifica el código y elimina toda una clase de errores de hilos.
Otra característica de Volley es la deduplicación automática de solicitudes. Si se añaden a la cola dos solicitudes GET idénticas a la misma URL con los mismos parámetros, Volley ejecuta solo una de ellas y devuelve la misma respuesta a ambos callbacks. Esto es especialmente útil para pantallas donde varios componentes solicitan independientemente los mismos datos — por ejemplo, un perfil de usuario que es necesario simultáneamente para el encabezado y un fragmento de configuración.
Cada solicitud pasa por una secuencia de pasos: crear una Request, añadirla a RequestQueue, verificar la caché (CacheDispatcher), ejecutar la solicitud HTTP (NetworkDispatcher), analizar la respuesta mediante Response.Listener, entregar el resultado al hilo de la UI. Cuando se cancela una solicitud (cancel), RequestQueue la elimina de la cola y evita que se invoquen los callbacks.
Volley también soporta RetryPolicy, que determina el número de reintentos en caso de fallos. DefaultRetryPolicy por defecto realiza un reintento con un tiempo de espera de 2.5 segundos. Para conexiones inestables, el número de reintentos se puede aumentar a 3 y el tiempo de espera a 10 segundos. Una RetryPolicy personalizada se implementa a través de la interfaz RetryPolicy con los métodos getCurrentTimeout, getCurrentRetryCount y retry.
Volley proporciona tipos de solicitudes predefinidos para formatos de datos comunes. Cada tipo implementa la clase abstracta Request<T> y define un método para analizar la respuesta. Para formatos personalizados, se puede crear un tipo propio sobrescribiendo el método parseNetworkResponse.
| Tipo de solicitud | Tipo de retorno | Propósito |
|---|---|---|
| StringRequest | String | Obtener una respuesta de texto sin formato |
| JsonObjectRequest | JSONObject | Analizar un objeto JSON |
| JsonArrayRequest | JSONArray | Analizar un array JSON |
| ImageRequest | Bitmap | Cargar y decodificar una imagen |
| ClearCacheRequest | — | Limpiar la caché de Volley |
Para trabajar con Gson o Kotlinx Serialization, se puede crear una Request<T> personalizada que utilice el analizador elegido en parseNetworkResponse. Esto permite recibir objetos tipados directamente, evitando el análisis manual de JSONObject. Este enfoque es especialmente útil para proyectos que ya utilizan serialización mediante Gson o Moshi.
Para enviar datos, Volley soporta tres tipos de cuerpo: JSONObject (mediante JsonObjectRequest con método POST), Form-encoded (mediante HashMap<String, String> en el constructor) y Multipart (mediante un MultipartRequest personalizado). Las solicitudes Multipart son útiles para cargar imágenes y archivos, pero requieren implementación manual ya que Volley no tiene soporte integrado para multipart/form-data, a diferencia de OkHttp o Dio.
Las limitaciones de Volley se hacen notables al trabajar con respuestas grandes. Volley carga toda la respuesta en memoria antes de pasarla al callback, lo que puede provocar OutOfMemoryError para archivos JSON de más de 10–20 MB. Para descargar archivos grandes, Volley no es adecuado — use DownloadManager u OkHttp con ResponseBody de transmisión. Volley tampoco soporta la reanudación de descargas interrumpidas (cabecera Range) ni funciona con protocolos de transmisión como Server-Sent Events o WebSocket en tiempo real.
Veamos un ejemplo básico — un StringRequest para obtener datos de un servidor. Primero, se crea una RequestQueue mediante Volley.newRequestQueue(context). Luego se forma una solicitud con una URL y callbacks de éxito y error.
val queue = Volley.newRequestQueue(context)
val request = StringRequest(
Request.Method.GET,
"https://api.github.com/users/octocat",
{ response ->
println("Respuesta: $response")
},
{ error ->
println("Error: ${error.message}")
}
)
queue.add(request)
Para una solicitud JSON, se utiliza JsonObjectRequest, que analiza automáticamente la respuesta en un JSONObject. Volley soporta solicitudes GET y POST. Para POST, se pasa un JSONObject en el cuerpo de la solicitud.
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("Creado: ${response.getString("id")}")
},
{ println("Error: $it") }
)
queue.add(request)
Para cancelar una solicitud, se utiliza el método cancel() o la cancelación grupal por etiqueta. Al cancelar, Volley no llama ni a onResponse ni a onErrorResponse, lo que evita actualizaciones de la interfaz después de salir de la pantalla. Esto es importante para prevenir fugas de memoria en Activity y Fragment.
request.tag = "profile_request"
queue.add(request)
// Cancelación al salir de la pantalla
queue.cancelAll("profile_request")
ImageLoader es una clase envolvente sobre RequestQueue, optimizada para cargar imágenes. Soporta caché en memoria (LruCache) y cancela automáticamente las solicitudes cuando se reutiliza ImageView en listas RecyclerView. ImageLoader también escala las imágenes al tamaño de la View, ahorrando memoria.
NetworkImageView es una View personalizada que se integra con ImageLoader y gestiona automáticamente la carga: muestra un placeholder durante la carga, lo reemplaza con un error en caso de fallo y cancela la solicitud cuando la View sale de la pantalla. DefaultImageUrlLoader carga una imagen por URL y la almacena en LruCache para una revisualización rápida.
Para usar ImageLoader, simplemente cree una instancia mediante ImageLoader(queue, ImageCache), donde ImageCache es una implementación de la interfaz ImageCache con LruCache interno. NetworkImageView en el diseño XML se vincula a ImageLoader mediante el método setImageUrl(), y toda la carga ocurre completamente automática sin código adicional para manejar placeholders y errores.
Crear una RequestQueue en cada Activity es un error común que provoca duplicación de hilos y confusión en la caché. Se recomienda crear RequestQueue una vez en Application o mediante una clase singleton. De lo contrario, cada pantalla tendrá su propio grupo de hilos y la caché se almacenará por separado para cada cola.
Ignorar la cancelación de solicitudes al rotar la pantalla. Al cambiar la configuración, la Activity se recrea y los callbacks de la Activity antigua continúan en memoria. Esto provoca fugas e intentos de actualizar una View destruida. Siempre cancele las solicitudes en onStop() mediante cancelAll() con una etiqueta específica de la Activity.
Volley no soporta HTTP/2 ni corrutinas — esto no es un error de uso sino una limitación arquitectónica. Volley fue creado en 2013 y no soporta protocolos modernos ni corrutinas de Kotlin. Para proyectos nuevos, Google recomienda usar Retrofit + OkHttp. Volley solo es adecuado para mantener proyectos heredados o aplicaciones simples con requisitos de red mínimos.
Preguntas frecuentes
Volley está obsoleto para proyectos nuevos — Google no ha actualizado la biblioteca desde 2017. Para aplicaciones modernas, use Retrofit + OkHttp o Ktor Client. Volley solo puede usarse para mantener código heredado existente o en proyectos educativos simples con tareas de red mínimas.
Falta de soporte para tecnologías modernas: HTTP/2, corrutinas de Kotlin, desarrollo multiplataforma y serialización tipada. Volley usa JSONObject y JSONArray sin tipos, lo que provoca errores en tiempo de ejecución cuando la estructura JSON no coincide con las expectativas.
A través de ImageLoader y NetworkImageView. ImageLoader usa LruCache para almacenamiento en caché de imágenes en memoria y cancela automáticamente las solicitudes cuando las vistas se reutilizan. NetworkImageView muestra un placeholder durante la carga y lo reemplaza con la imagen cargada o un indicador de error.
Técnicamente sí — mediante un envoltorio suspendCoroutine { } sobre los callbacks de Volley. Pero esto no ofrece ventajas ya que Volley no soporta cancelación basada en la cancelación de corrutinas ni funciona con Dispatchers.IO directamente. Es mejor usar Ktor Client con soporte nativo de corrutinas.
El tiempo de espera se configura mediante RetryPolicy. Por defecto, DefaultRetryPolicy usa un tiempo de espera de 2.5 segundos y un reintento. Para cambiar los parámetros: request.retryPolicy = DefaultRetryPolicy(10000, 1, 1.0f) — 10 segundos de tiempo de espera, un intento.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también