本课介绍了如何为不具有开箱即用的 Volley 支持的类型实现您自己的自定义请求类型。
编写自定义请求
大多数请求的工具箱中都有可供使用的实现;如果您的响应是字符串、图片或 JSON,那么您可能不需要实现自定义Request
。
如果您确实需要实现自定义请求,则只需执行以下操作即可:
- 扩展
Request<T>
类,其中<T>
表示请求期望的已解析响应的类型。因此,例如,如果已解析的响应是字符串,请通过扩展Request<String>
创建自定义请求。如需查看扩展Request<T>
的示例,请参阅 Volley 工具箱类StringRequest
和ImageRequest
。 - 实现抽象方法
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 提供 JsonArrayRequest
和 JsonArrayObject
类供您使用。如需了解详情,请参阅发出标准请求。