Cómo configurar RequestQueue

En la lección anterior, se mostraba cómo usar el método de conveniencia Volley.newRequestQueue para configurar una RequestQueue y aprovechar los comportamientos predeterminados de Volley. En esta lección, se explican los pasos explícitos para crear una RequestQueue, que te permitirán ofrecer un comportamiento personalizado.

En esta lección, también se describe la práctica recomendada para crear una RequestQueue como un singleton, lo que hace que la RequestQueue dure toda la vida útil de tu app.

Cómo configurar una red y una caché

Una RequestQueue necesita dos cosas a fin de realizar su trabajo: una red mediante la cual transportar las solicitudes y una caché para administrar el almacenamiento en caché. Hay implementaciones estándar de estas en la caja de herramientas de Volley: DiskBasedCache proporciona una caché de un archivo por respuesta con un índice en la memoria y BasicNetwork proporciona transporte de red basado en tu cliente HTTP preferido.

BasicNetwork es la implementación de red predeterminada de Volley. Se debe inicializar una BasicNetwork con el cliente HTTP que tu app usa para conectarse a la red. Por lo general, es una HttpURLConnection.

En este fragmento, se muestran los pasos para configurar una RequestQueue:

Kotlin

    // Instantiate the cache
    val cache = DiskBasedCache(cacheDir, 1024 * 1024) // 1MB cap

    // Set up the network to use HttpURLConnection as the HTTP client.
    val network = BasicNetwork(HurlStack())

    // Instantiate the RequestQueue with the cache and network. Start the queue.
    val requestQueue = RequestQueue(cache, network).apply {
        start()
    }

    val url = "http://www.example.com"

    // Formulate the request and handle the response.
    val stringRequest = StringRequest(Request.Method.GET, url,
             Response.Listener<String> { response ->
                // Do something with the response
            },
            Response.ErrorListener { error ->
                // Handle error
                textView.text = "ERROR: %s".format(error.toString())
            })

    // Add the request to the RequestQueue.
    requestQueue.add(stringRequest)

    // ...
    

Java

    RequestQueue requestQueue;

    // Instantiate the cache
    Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap

    // Set up the network to use HttpURLConnection as the HTTP client.
    Network network = new BasicNetwork(new HurlStack());

    // Instantiate the RequestQueue with the cache and network.
    requestQueue = new RequestQueue(cache, network);

    // Start the queue
    requestQueue.start();

    String url ="http://www.example.com";

    // Formulate the request and handle the response.
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            // Do something with the response
        }
    },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // Handle error
        }
    });

    // Add the request to the RequestQueue.
    requestQueue.add(stringRequest);

    // ...
    

Si solo necesitas realizar una solicitud única y no quieres abandonar el conjunto de subprocesos, puedes crear la RequestQueue en donde sea que la necesites y llamar a stop() en la RequestQueue cuando haya vuelto tu respuesta o error con el método Volley.newRequestQueue() que se describe en Cómo enviar una solicitud simple. Pero el caso práctico más común es crear la RequestQueue como singleton para mantenerla en funcionamiento durante toda la vida de tu app, como se describe en la siguiente sección.

Cómo usar un patrón singleton

Si tu app usa la red de manera constante, es probable que sea más eficiente configurar una sola instancia de RequestQueue que se extienda durante toda su vida útil. Puedes lograrlo de varias maneras. El enfoque recomendado es implementar una clase singleton que encapsule la RequestQueuey otras funcionalidades de Volley. Otro enfoque es crear subclases Application y configurar la RequestQueue in Application.onCreate(). Sin embargo, este enfoque no es recomemdable; un singleton estático puede proporcionar la misma funcionalidad de manera más modular.

Un concepto clave es que se deben crear instancias de la RequestQueue con el contexto de la Application y no de la Activity. De esta manera, se garantiza que la RequestQueue dure todo el ciclo de vida de la app, en lugar de volver a crearse cada vez que la actividad vuelva a generarse (por ejemplo, cuando el usuario rota el dispositivo).

Este es un ejemplo de una clase singleton que proporciona las funciones RequestQueue y ImageLoader:

Kotlin

    class MySingleton constructor(context: Context) {
        companion object {
            @Volatile
            private var INSTANCE: MySingleton? = null
            fun getInstance(context: Context) =
                INSTANCE ?: synchronized(this) {
                    INSTANCE ?: MySingleton(context).also {
                        INSTANCE = it
                    }
                }
        }
        val imageLoader: ImageLoader by lazy {
            ImageLoader(requestQueue,
                    object : ImageLoader.ImageCache {
                        private val cache = LruCache<String, Bitmap>(20)
                        override fun getBitmap(url: String): Bitmap {
                            return cache.get(url)
                        }
                        override fun putBitmap(url: String, bitmap: Bitmap) {
                            cache.put(url, bitmap)
                        }
                    })
        }
        val requestQueue: RequestQueue by lazy {
            // applicationContext is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            Volley.newRequestQueue(context.applicationContext)
        }
        fun <T> addToRequestQueue(req: Request<T>) {
            requestQueue.add(req)
        }
    }
    

Java

    public class MySingleton {
        private static MySingleton instance;
        private RequestQueue requestQueue;
        private ImageLoader imageLoader;
        private static Context ctx;

        private MySingleton(Context context) {
            ctx = context;
            requestQueue = getRequestQueue();

            imageLoader = new ImageLoader(requestQueue,
                    new ImageLoader.ImageCache() {
                private final LruCache<String, Bitmap>
                        cache = new LruCache<String, Bitmap>(20);

                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }

                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
        }

        public static synchronized MySingleton getInstance(Context context) {
            if (instance == null) {
                instance = new MySingleton(context);
            }
            return instance;
        }

        public RequestQueue getRequestQueue() {
            if (requestQueue == null) {
                // getApplicationContext() is key, it keeps you from leaking the
                // Activity or BroadcastReceiver if someone passes one in.
                requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
            }
            return requestQueue;
        }

        public <T> void addToRequestQueue(Request<T> req) {
            getRequestQueue().add(req);
        }

        public ImageLoader getImageLoader() {
            return imageLoader;
        }
    }
    

Aquí tienes algunos ejemplos de cómo realizar operaciones de RequestQueuecon la clase singleton:

Kotlin

    // Get a RequestQueue
    val queue = MySingleton.getInstance(this.applicationContext).requestQueue

    // ...

    // Add a request (in this example, called stringRequest) to your RequestQueue.
    MySingleton.getInstance(this).addToRequestQueue(stringRequest)
    

Java

    // Get a RequestQueue
    RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
        getRequestQueue();

    // ...

    // Add a request (in this example, called stringRequest) to your RequestQueue.
    MySingleton.getInstance(this).addToRequestQueue(stringRequest);