1.进度接口
public interface ProgressListener {
void update(String url, long bytesRead, long contentLength, boolean done);
}
2.重写ResponeBody
public class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
private final String url;
ProgressResponseBody(String url, ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
this.url = url;
}
@Override
public MediaType contentType() {
return responseBody.contentType();
}
@Override
public long contentLength() {
return responseBody.contentLength();
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(final 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;
progressListener.update(url, totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
3.重写拦截器
public class ProgressInterceptor implements Interceptor {
private ProgressListener progressListener;
public ProgressInterceptor(ProgressListener progressListener) {
this.progressListener = progressListener;
}
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(chain.request().url().url().toString(), originalResponse.body(), progressListener))
.build();
}
}
4.构建OkHttpClient时添加NetworkInterceptor
okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(new ProgressInterceptor(new ProgressListener() {
@Override
public void update(String url, long bytesRead, long contentLength,
boolean done) {
//这里处理进度
}
}))
....
这个拦截器是在onNext之前生效的,会在文件全部下载完成后调用onNext,然后获取一下输入流写入文件就好了。
5.一些问题
1.下载个王者荣耀OOM了(已经添加@Streaming),查了一下说是Interceptor.setLevel()不要设置Body,还没测试。
2.observeOn()在主线程时,UI刷新不了。没搞懂