Participe do evento ⁠#Android11: apresentação de lançamento da versão Beta no dia 3 de junho.

Configurar RequestQueue

A lição anterior mostrou como usar o método de conveniência Volley.newRequestQueue para configurar um RequestQueue, aproveitando os comportamentos padrão do Volley. Esta lição traz orientações sobre as etapas explícitas da criação de uma RequestQueue, para que você disponibilize o próprio comportamento personalizado.

Esta lição também descreve a prática recomendada para criar uma RequestQueue como um singleton, para que a RequestQueue tenha uma duração equivalente à vida útil do seu app.

Configurar rede e cache

Uma RequestQueue tem duas exigências para funcionar: uma rede que faça o transporte das solicitações e um cache que lide com o armazenamento. Existem implementações padrão dessas exigências disponíveis na caixa de ferramentas do Volley: DiskBasedCache oferece um cache de um arquivo por resposta com um índice na memória, enquanto BasicNetwork oferece um transporte de rede baseado no seu cliente HTTP preferencial.

A BasicNetwork é a implementação de rede padrão do Volley. Uma BasicNetwork precisa ser inicializada com o cliente HTTP que seu app está usando para se conectar à rede. Normalmente, essa conexão é HttpURLConnection.

Este snippet mostra as etapas envolvidas na configuração de uma 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);

    // ...
    

Se você só precisar fazer uma solicitação única e não quiser sair do pool de linhas de execução, poderá criar o RequestQueue sempre que precisar e chamar stop() no RequestQueue assim que a resposta ou erro retornar, usando o método Volley.newRequestQueue() descrito em Como enviar uma solicitação simples. Mas o caso de uso mais comum é criar o RequestQueue como um singleton para mantê-lo em execução durante a vida útil do app, conforme descrito na próxima seção.

Usar um padrão de singleton

Se seu app faz uso constante da rede, provavelmente é mais eficiente configurar uma única instância de RequestQueue que dure a vida útil do app. Você pode conseguir isso de várias maneiras. A abordagem recomendada é implementar uma classe de singleton que encapsule RequestQueue e outros recursos do Volley. Outra abordagem é definir a subclasse Application e a configuração de RequestQueue em Application.onCreate(). No entanto, essa segunda abordagem não é recomendada, uma vez que um singleton estático pode oferecer a mesma funcionalidade de maneira mais modular.

Um conceito importante é que o RequestQueue precisa ser instanciado com o contexto Application, não um contexto Activity. Isso garante que a RequestQueue tenha uma duração equivalente à vida útil do app, em vez de ser recriada toda vez que a atividade é criada novamente (por exemplo, quando o usuário gira o dispositivo).

Veja o exemplo de uma classe singleton que fornece a funcionalidade RequestQueue e 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;
        }
    }
    

Estes são alguns exemplos de como realizar operações RequestQueue usando a classe de 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);