好的,所以我想出了一个涉及编辑 Volley 本身的解决方案。这是一个演练:
网络响应不能再保存字节数组了。它需要保存一个输入流。这样做会立即破坏所有请求实现,因为它们依赖于持有公共字节数组成员的 NetworkResponse。我发现解决此问题的侵入性最小的方法是在 NetworkResponse 中添加一个“toByteArray”方法,然后进行一些重构,使对字节数组的任何引用都使用此方法,而不是删除的字节数组成员。这意味着输入流到字节数组的转换发生在响应解析期间。我不完全确定这样做的长期影响是什么,因此一些单元测试/社区输入将在这里提供巨大帮助。代码如下:
public class NetworkResponse {
/**
* Creates a new network response.
* @param statusCode the HTTP status code
* @param data Response body
* @param headers Headers returned with this response, or null for none
* @param notModified True if the server returned a 304 and the data was already in cache
*/
public NetworkResponse(int statusCode, inputStream data, Map<String, String> headers,
boolean notModified, ByteArrayPool byteArrayPool, int contentLength) {
this.statusCode = statusCode;
this.data = data;
this.headers = headers;
this.notModified = notModified;
this.byteArrayPool = byteArrayPool;
this.contentLength = contentLength;
}
public NetworkResponse(byte[] data) {
this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false);
}
public NetworkResponse(byte[] data, Map<String, String> headers) {
this(HttpStatus.SC_OK, data, headers, false);
}
/** The HTTP status code. */
public final int statusCode;
/** Raw data from this response. */
public final InputStream inputStream;
/** Response headers. */
public final Map<String, String> headers;
/** True if the server returned a 304 (Not Modified). */
public final boolean notModified;
public final ByteArrayPool byteArrayPool;
public final int contentLength;
// method taken from BasicNetwork with a few small alterations.
public byte[] toByteArray() throws IOException, ServerError {
PoolingByteArrayOutputStream bytes =
new PoolingByteArrayOutputStream(byteArrayPool, contentLength);
byte[] buffer = null;
try {
if (inputStream == null) {
throw new ServerError();
}
buffer = byteArrayPool.getBuf(1024);
int count;
while ((count = inputStream.read(buffer)) != -1) {
bytes.write(buffer, 0, count);
}
return bytes.toByteArray();
} finally {
try {
// Close the InputStream and release the resources by "consuming the content".
// Not sure what to do about the entity "consumeContent()"... ideas?
inputStream.close();
} catch (IOException e) {
// This can happen if there was an exception above that left the entity in
// an invalid state.
VolleyLog.v("Error occured when calling consumingContent");
}
byteArrayPool.returnBuf(buffer);
bytes.close();
}
}
}
然后要准备 NetworkResponse,我们需要编辑 BasicNetwork 以正确创建 NetworkResponse(在 BasicNetwork.performRequest 内):
int contentLength = 0;
if (httpResponse.getEntity() != null)
{
responseContents = httpResponse.getEntity().getContent(); // responseContents is now an InputStream
contentLength = httpResponse.getEntity().getContentLength();
}
...
return new NetworkResponse(statusCode, responseContents, responseHeaders, false, mPool, contentLength);
就是这样。一旦网络响应中的数据成为输入流,我就可以构建自己的请求,将其直接解析为文件输出流,该输出流仅包含一个小的内存缓冲区。
从一些初步测试来看,这似乎工作正常而不会损害其他组件,但是像这样的更改可能需要一些更密集的测试和同行评审,所以我会留下这个答案不标记为正确,直到更多人们参与进来,或者我认为它足够可靠。
请随时对此答案发表评论和/或自己发布答案。这感觉像是 Volley 设计中的一个严重缺陷,如果你看到这个设计的缺陷,或者自己能想出更好的设计,我认为它会对每个人都有好处。