Volley-直接下载到文件(在内存字节数组中没有) [英] Volley - download directly to file (no in memory byte array)

查看:120
本文介绍了Volley-直接下载到文件(在内存字节数组中没有)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Android上正在使用的项目中将Volley用作网络堆栈.我的部分要求是下载可能非常大的文件并将其保存在文件系统中.

I'm using Volley as my network stack in a project I'm working on in Android. Part of my requirements is to download potentially very large files and save them on the file system.

我一直在看齐射的实现,看来齐射的唯一方法是将整个文件下载到一个潜在的大字节数组中,然后将该字节数组的处理推迟到某些回调处理程序中.

Ive been looking at the implementation of volley, and it seems that the only way volley works is it downloads an entire file into a potentially massive byte array and then defers handling of this byte array to some callback handler.

由于这些文件可能很大,因此我担心下载过程中出现内存不足错误.

Since these files can be very large, I'm worried about an out of memory error during the download process.

有没有一种方法可以让凌空处理将http输入流中的所有字节直接处理为文件输出流?还是这需要我实现自己的网络对象?

Is there a way to tell volley to process all bytes from an http input stream directly into a file output stream? Or would this require me to implement my own network object?

我在网上找不到有关此内容的任何材料,因此任何建议将不胜感激.

I couldn't find any material about this online, so any suggestions would be appreciated.

推荐答案

好的,所以我想出了一个解决方案,其中涉及编辑Volley本身.这是一个遍历:

Okay, so I've come up with a solution which involves editing Volley itself. Here's a walk through:

网络响应不再包含字节数组.它需要保存输入流.这样做立即中断了所有请求的实现,因为它们依赖于持有公共字节数组成员的NetworkResponse.我发现处理此问题的侵入性最小的方法是在NetworkResponse中添加"toByteArray"方法,然后进行一些重构,使对字节数组的任何引用都使用此方法,而不是使用已删除的字节数组成员.这意味着在响应解析期间会发生输入流到字节数组的过渡.我不确定这会带来什么长期影响,因此在这里进行一些单元测试/社区投入将是巨大的帮助.这是代码:

Network response can't hold a byte array anymore. It needs to hold an input stream. Doing this immediately breaks all request implementations, since they rely on NetworkResponse holding a public byte array member. The least invasive way I found to deal with this is to add a "toByteArray" method inside NetworkResponse, and then do a little refactoring, making any reference to a byte array use this method, rather than the removed byte array member. This means that the transition of the input stream to a byte array happens during the response parsing. I'm not entirely sure what the long term effects of this are, and so some unit testing / community input would be a huge help here. Here's the code:

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内部):

Then to prepare the NetworkResponse, we need to edit the BasicNetwork to create the NetworkResponse correctly (inside 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);

就是这样.一旦网络响应中的数据成为输入流,我就可以构建自己的请求,将其直接解析为仅包含较小的内存缓冲区的文件输出流.

That's it. Once the data inside network response is an input stream, I can build my own requests which can parse it directly into a file output stream which only hold a small in-memory buffer.

从一些初始测试来看,这似乎可以正常工作,而且不会损害其他组件,但是,像这样的更改可能需要进行更深入的测试和测试.同行评审,所以直到更多的人参与进来,否则我将不把这个答案标记为正确,否则我将认为它足够强大以至于可以依靠.

From a few initial tests, this seems to be working alright without harming other components, however a change like this probably requires some more intensive testing & peer reviewing, so I'm going to leave this answer not marked as correct until more people weigh in, or I see it's robust enough to rely on.

请随时对此答案发表评论和/或发表答案.这感觉像是Volley设计中的一个严重缺陷,如果您发现此设计存在缺陷,或者可以想到更好的设计,那么我认为它将使所有人受益.

Please feel free to comment on this answer and/or post answers yourselves. This feels like a serious flaw in Volley's design, and if you see flaws with this design, or can think of better designs yourselves, I think it would benefit everyone.

这篇关于Volley-直接下载到文件(在内存字节数组中没有)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆