使用Retrofit 2下载文件时出现内存不足的问题

5

我有一个PDF阅读器应用程序,需要下载大型PDF文件(例如136MB),我正在使用retrofit2-beta2进行此过程。问题是我总是会因内存不足而出错。如何告诉retrofit我将要下载大文件,请直接将字节流给我?

我的接口是:

@GET("url")
Call<ResponseBody> getData(params);

我有一个ProgressResponseBody类,它扩展了ResponseBody,并在此处设置了一个progressListener,以便能够刷新进度条。
在onResponse函数中,我只需获取InputStream。
InputStream input = response.body().byteStream();
FileOutputStream out = new FileOutputStream(file);
int bufferSize=1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while (len = input.read(buffer) != -1) {
    out.write(buffer,0,len);
} 
if(out!=null)
    out.close();

更新

我已经在接口中添加了@Stream,但现在在ProgressResponseBody.java文件中遇到了NetworkOnMainThreadException异常。错误是在超级.read(sink,byteCount); 行中抛出的。如何将其放入单独的线程中?

@Override
    public BufferedSource source() throws IOException {
        if (bufferedSource == null) {
            bufferedSource = Okio.buffer(source(responseBody.source()));
        }
        return bufferedSource;
    }

    private Source source(Source source) {
        return new ForwardingSource(source) {
            long totalBytesRead = 0L;

            @Override
            public long read(Buffer sink, long byteCount) throws IOException {
                long bytesRead = super.read(sink, byteCount);
                totalBytesRead += bytesRead != -1 ? bytesRead : 0;
                progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
                return bytesRead;
            }
        };
    }
1个回答

5

在调用中添加@Streaming注释以获取原始的ResponseBody

@Streaming
@GET("url")
Call<ResponseBody> getData(params);

我已经尝试过了,但是我遇到了“在主线程上的网络异常”(NetworkOnMainThread exception)... 但这个调用应该是异步的,不是吗? - MegaX
这是因为当你使用@Streaming时,response.body()是网络调用,所以你现在需要将其移出主线程的责任。对于普通调用,Retrofit会为您完成此操作。将响应体的处理移动到新线程(通过AsyncTask或类似方式)。 - iagreen
不好,我做了但没有帮助... 我已经更新了问题。 - MegaX
好的,你是对的,这确实有所帮助,只是需要将正确的内容放到一个单独的线程中。谢谢! - MegaX
我的文件在下载一段时间后停止了,显示暂停线程由于连接超时。如何解决大文件可能需要不确定时间的这个问题? - Usman Rana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接