Retrofit(重构——下载大文件)

前一篇大概讲解了关于图片的下载,是属于小型文件,当我们用同样的框架,去下载大型文件的时候,意外就发生了,oom了。
别怕,亮剑吧!

  • @Streaming
@Multipart
@Streaming   @POST("download/AppStore/01a3bd5737f2e4fcc0c1939b4798b259b3c31247e/com.supercell.clashroyale.mi.apk")
    Observable getXlGetLargeFile(@Part("p") RequestBody requestBody);

堪称大文件下载核武器,此apk有90M,不小了吧。Streaming意味着立刻传递字节码,而不需要把整个文件读进内存。值得注意的是,如果你使用了@Streaming,并且会抛出android.os.NetworkOnMainThreadException异常,那么请将你的请求放到子线程中去。

  • 滚蛋吧,log
    如果以上的操作还不能避免oom的话,那么请检查一下okhttp中是不是配置了httplog,如果有,则去掉。

JakeWharton commented on Jun 24, 2014
By calling .setLogLevel(RestAdapter.LogLevel.FULL) you are forcing Retrofit to buffer the entire request body into memory so that it can log. That’s what the call to readBodyToBytesIfNecessary in the stack trace is doing.
Enabling logging like this should only be done when debugging.

这是jw大神说的一句话,所以我们在下载大文件的时候就乖乖哒把log去掉吧。

以上解决了大文件下载问题,下面加个功能,进度显示,从拦截器入口。

  • 重写ResponseBody
public class ProgressResponseBody extends ResponseBody
{
    private final ResponseBody responseBody;
   // private final ProgressListener progressListener;
    private BufferedSource bufferedSource;

    public ProgressResponseBody(ResponseBody responseBody)
    {
        this.responseBody = responseBody;
      //  this.progressListener = progressListener;
    }

    @Override
    public MediaType contentType()
    {
        return responseBody.contentType();
    }

    @Override
    public long contentLength() throws IOException {
        return responseBody.contentLength();
    }

    @Override
    public BufferedSource source()
    {
        if(bufferedSource == null)
        {
            try {
                bufferedSource = Okio.buffer(source(responseBody.source()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        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);
                // read() returns the number of bytes read, or -1 if this source is exhausted.
                totalBytesRead += bytesRead != -1 ? bytesRead : 0;
                App.getBus().post(new ProgressUpdateEvent(totalBytesRead, responseBody.contentLength(), bytesRead == -1));
               // progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
                return bytesRead;
            }
        };
    }
}
  • 重写拦截器
public class ProgressInterceptor implements Interceptor
{
   // private ProgressListener progressListener;


  /*  public ProgressInterceptor(ProgressListener progressListener)
    {
        this.progressListener = progressListener;
    }*/

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException
    {
        Response originalResponse = chain.proceed(chain.request());
        return originalResponse.newBuilder().body(new ProgressResponseBody(originalResponse.body())).build();
    }
}
  • 配置okhttp
  client.interceptors().add(progressInterceptor);//进度条
  • 接收进度更新
 public void onEventMainThread(ProgressUpdateEvent progressUpdateEvent) {
      Log.e("yan",progressUpdateEvent.getbytesRead()+"!!!!!!!!!!!!!!!!");

    }

附:别人的小demo,若文件太大,出现bug,则采取以上措施即可解决。

你可能感兴趣的:(Retrofit(重构——下载大文件))