Cómo implementar una solicitud personalizada

En esta lección, se describe cómo implementar tus propios tipos de solicitudes personalizadas para los tipos que no incluyen compatibilidad integrada con Volley.

Cómo escribir una solicitud personalizada

La mayoría de las solicitudes incluyen implementaciones listas para usar en la caja de herramientas; si tu respuesta es una string, una imagen o un JSON, probablemente no necesites implementar una Request personalizada.

En los casos en los que necesites implementar una solicitud personalizada, deberás hacer lo siguiente:

  • Extiende la clase Request<T>, en la que <T> representa el tipo de respuesta analizada que espera la solicitud. Por lo tanto, si, por ejemplo, la respuesta analizada es una string, debes extender Request<String> para crear tu solicitud personalizada. Consulta las clases StringRequest y ImageRequest de la caja de herramientas de Volley para obtener ejemplos de la Request<T> que se extiende.
  • Implementa los métodos abstractos parseNetworkResponse() y deliverResponse(), como se describe con mayor detalle a continuación.

parseNetworkResponse

Una Response encapsula una respuesta analizada que se entregará para un tipo específico (como una string, una imagen o un elemento JSON). A continuación, se muestra una implementación de ejemplo de parseNetworkResponse().

Kotlin

    override fun parseNetworkResponse(response: NetworkResponse?): Response<T> {
        return try {
            val json = String(
                    response?.data ?: ByteArray(0),
                    Charset.forName(HttpHeaderParser.parseCharset(response?.headers)))
            Response.success(
                    gson.fromJson(json, clazz),
                    HttpHeaderParser.parseCacheHeaders(response))
        }
        // handle errors
    // ...
    }
    

Java

    @Override
    protected Response<T> parseNetworkResponse(
            NetworkResponse response) {
        try {
            String json = new String(response.data,
            HttpHeaderParser.parseCharset(response.headers));
        return Response.success(gson.fromJson(json, clazz),
        HttpHeaderParser.parseCacheHeaders(response));
        }
        // handle errors
    // ...
    }
    

Ten en cuenta lo siguiente:

  • parseNetworkResponse() toma como su parámetro a NetworkResponse, que contiene la carga útil de la respuesta como un byte[], un código de estado HTTP y encabezados de respuesta.
  • Tu implementación debe mostrar una Response<T>, que contiene tu objeto de respuesta con el tipo definido y metadatos almacenados en caché o un error, en el caso de que falle el análisis.

Si tu protocolo tiene semánticas almacenadas en caché que no son estándar, puedes crear una Cache.Entry por tu cuenta, pero para la mayoría de las solicitudes bastará con lo siguiente:

Kotlin

    return Response.success(myDecodedObject,
            HttpHeaderParser.parseCacheHeaders(response))
    

Java

    return Response.success(myDecodedObject,
            HttpHeaderParser.parseCacheHeaders(response));
    

Volley llama a parseNetworkResponse() desde un subproceso de trabajo. De esta manera, se garantiza que las operaciones de análisis costosas, como la decodificación de un JPEG en un mapa de bits, no bloqueen el subproceso de IU.

deliverResponse

Volley te devuelve la llamada en el subproceso principal con el objeto que mostraste en parseNetworkResponse(). La mayoría de las solicitudes invocan una interfaz de devolución de llamada como la siguiente:

Kotlin

    override fun deliverResponse(response: T) = listener.onResponse(response)
    

Java

    protected void deliverResponse(T response) {
            listener.onResponse(response);
    

Ejemplo: GsonRequest

Gson es una biblioteca para convertir objetos Java en JSON y viceversa, por medio de la reflexión. Puedes definir objetos Java que tienen el mismo nombre que sus claves JSON correspondientes, pasar la clase de objeto a Gson y este completará los campos por ti. Aquí tienes una implementación completa de una solicitud de Volley que usa Gson para realizar el análisis:

Kotlin

    /**
     * Make a GET request and return a parsed object from JSON.
     *
     * @param url URL of the request to make
     * @param clazz Relevant class object, for Gson's reflection
     * @param headers Map of request headers
     */
    class GsonRequest<T>(
            url: String,
            private val clazz: Class<T>,
            private val headers: MutableMap<String, String>?,
            private val listener: Response.Listener<T>,
            errorListener: Response.ErrorListener
    ) : Request<T>(Method.GET, url, errorListener) {
        private val gson = Gson()

        override fun getHeaders(): MutableMap<String, String> = headers ?: super.getHeaders()

        override fun deliverResponse(response: T) = listener.onResponse(response)

        override fun parseNetworkResponse(response: NetworkResponse?): Response<T> {
            return try {
                val json = String(
                        response?.data ?: ByteArray(0),
                        Charset.forName(HttpHeaderParser.parseCharset(response?.headers)))
                Response.success(
                        gson.fromJson(json, clazz),
                        HttpHeaderParser.parseCacheHeaders(response))
            } catch (e: UnsupportedEncodingException) {
                Response.error(ParseError(e))
            } catch (e: JsonSyntaxException) {
                Response.error(ParseError(e))
            }
        }
    }
    

Java

    public class GsonRequest<T> extends Request<T> {
        private final Gson gson = new Gson();
        private final Class<T> clazz;
        private final Map<String, String> headers;
        private final Listener<T> listener;

        /**
         * Make a GET request and return a parsed object from JSON.
         *
         * @param url URL of the request to make
         * @param clazz Relevant class object, for Gson's reflection
         * @param headers Map of request headers
         */
        public GsonRequest(String url, Class<T> clazz, Map<String, String> headers,
                Listener<T> listener, ErrorListener errorListener) {
            super(Method.GET, url, errorListener);
            this.clazz = clazz;
            this.headers = headers;
            this.listener = listener;
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            return headers != null ? headers : super.getHeaders();
        }

        @Override
        protected void deliverResponse(T response) {
            listener.onResponse(response);
        }

        @Override
        protected Response<T> parseNetworkResponse(NetworkResponse response) {
            try {
                String json = new String(
                        response.data,
                        HttpHeaderParser.parseCharset(response.headers));
                return Response.success(
                        gson.fromJson(json, clazz),
                        HttpHeaderParser.parseCacheHeaders(response));
            } catch (UnsupportedEncodingException e) {
                return Response.error(new ParseError(e));
            } catch (JsonSyntaxException e) {
                return Response.error(new ParseError(e));
            }
        }
    }
    

Volley proporciona las clases JsonArrayRequest y JsonArrayObject listas para usar si prefieres usar ese enfoque. Para obtener más información, consulta Cómo realizar una solicitud estándar.