实现自定义请求

本课介绍了如何为没有开箱后即支持 Volley 的类型实现您自己的自定义请求类型。

编写自定义请求

大多数请求的工具箱中都有可供使用的实现;如果您的响应是字符串、图片或 JSON,那么您可能不需要实现自定义 Request

如果您确实需要实现自定义请求,则只需执行以下操作即可:

  • 扩展 Request<T> 类,其中 <T> 表示请求期望的已解析响应的类型。因此,如果已解析的响应是字符串,请通过扩展 Request<String> 创建自定义请求。如要查看扩展 Request<T> 的示例,请参阅 Volley 工具箱类 StringRequestImageRequest
  • 实现抽象方法 parseNetworkResponse()deliverResponse(),详细说明如下所示。

parseNetworkResponse

Response 封装给定类型(例如字符串、图片或 JSON)的用于传送的已解析响应。下面的示例展示了 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
    // ...
    }
    

请注意以下几点:

  • parseNetworkResponse()NetworkResponse 作为其参数,其中包含响应负载作为字节 []、HTTP 状态代码以及响应标头。
  • 您的实现必须返回 Response<T>,其中包含您输入的响应对象和缓存元数据,或者解析失败时出现的错误。

如果您的协议具有非标准缓存语义,您可以自行构建一个 Cache.Entry,但大多数请求都支持下述示例:

Kotlin

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

Java

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

Volley 从工作线程调用 parseNetworkResponse()。这样可确保昂贵的解析操作(例如将 JPEG 解码为位图)不会阻止界面线程。

deliverResponse

Volley 使用您在 parseNetworkResponse() 中返回的对象在主线程上回调您。大多数请求都会在这里调用回调接口,例如:

Kotlin

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

Java

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

示例:GsonRequest

GSON 是一个内容库,使用反射功能在 Java 对象和 JSON 之间来回转换。您可以定义与其对应 JSON 密钥具有相同名称的 Java 对象,向 GSON 传递类对象,而 GSON 会为您填充字段。以下是使用 GSON 进行解析的 Volley 请求的完整实现:

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 提供 JsonArrayRequestJsonArrayObject 类供您使用。如需了解详情,请参阅发出标准请求