OkHttp download progress does not sync with actual download

I am trying to track download progress using OkHttp. I created a custom RequestBody with the following body ( this answer is kindly provided), which writes to sink and post the progress.

 public class CountingFileRequestBody extends RequestBody { private static final String TAG = "CountingFileRequestBody"; private final ProgressListener listener; private final String key; private final MultipartBody multipartBody; protected CountingSink mCountingSink; public CountingFileRequestBody(MultipartBody multipartBody, String key, ProgressListener listener) { this.multipartBody = multipartBody; this.listener = listener; this.key = key; } @Override public long contentLength() throws IOException { return multipartBody.contentLength(); } @Override public MediaType contentType() { return multipartBody.contentType(); } @Override public void writeTo(BufferedSink sink) throws IOException { mCountingSink = new CountingSink(sink); BufferedSink bufferedSink = Okio.buffer(mCountingSink); multipartBody.writeTo(bufferedSink); bufferedSink.flush(); } public interface ProgressListener { void transferred(String key, int num); } protected final class CountingSink extends ForwardingSink { private long bytesWritten = 0; public CountingSink(Sink delegate) { super(delegate); } @Override public void write(Buffer source, long byteCount) throws IOException { bytesWritten += byteCount; listener.transferred(key, (int) (100F * bytesWritten / contentLength())); super.write(source, byteCount); delegate().flush(); // I have added this line to manually flush the sink } } } 

The problem is that the receiver is recorded so that it immediately drops, without actually sending buffered bytes to the server. The value of my progress reaches its end long before the actual load.
Note: Some say that the shell should be cleaned at each iteration for the bytes that will actually be loaded, but it does not work for me.

+5
source share
1 answer

I know this is an old post, but for someone with the same problem I adapted a helper class (ProgressOutputStream) from this library: https://github.com/lizhangqu/CoreProgress , and my working code looks like this: (works to download files and to download json too)

 import java.io.IOException; import okhttp3.MediaType; import okhttp3.RequestBody; import okio.BufferedSink; import okio.Okio; public class UploadProgressRequestBody extends RequestBody { private final RequestBody requestBody; private final ProgressListener progressListener; public UploadProgressRequestBody(RequestBody requestBody) { this.requestBody = requestBody; this.progressListener = getDefaultProgressListener(); } @Override public MediaType contentType() { return requestBody.contentType(); } @Override public long contentLength() { try { return requestBody.contentLength(); } catch (IOException e) { e.printStackTrace(); } return -1; } @Override public void writeTo(BufferedSink sink) throws IOException { if (progressListener == null) { requestBody.writeTo(sink); return; } ProgressOutputStream progressOutputStream = new ProgressOutputStream(sink.outputStream(), progressListener, contentLength()); BufferedSink progressSink = Okio.buffer(Okio.sink(progressOutputStream)); requestBody.writeTo(progressSink); progressSink.flush(); } interface ProgressListener { void update(long bytesWritten, long contentLength); } private ProgressListener getDefaultProgressListener(){ ProgressListener progressListener = new UploadProgressRequestBody.ProgressListener() { @Override public void update(long bytesRead, long contentLength) { System.out.println("bytesRead: "+bytesRead); System.out.println("contentLength: "+contentLength); System.out.format("%d%% done\n", (100 * bytesRead) / contentLength); } }; return progressListener; } } 

============

 import java.io.IOException; import java.io.OutputStream; class ProgressOutputStream extends OutputStream { private final OutputStream stream; private final UploadProgressRequestBody.ProgressListener listener; private long total; private long totalWritten; ProgressOutputStream(OutputStream stream, UploadProgressRequestBody.ProgressListener listener, long total) { this.stream = stream; this.listener = listener; this.total = total; } @Override public void write(byte[] b, int off, int len) throws IOException { this.stream.write(b, off, len); if (this.total < 0) { this.listener.update(-1, -1); return; } if (len < b.length) { this.totalWritten += len; } else { this.totalWritten += b.length; } this.listener.update(this.totalWritten, this.total); } @Override public void write(int b) throws IOException { this.stream.write(b); if (this.total < 0) { this.listener.update(-1, -1); return; } this.totalWritten++; this.listener.update(this.totalWritten, this.total); } @Override public void close() throws IOException { if (this.stream != null) { this.stream.close(); } } @Override public void flush() throws IOException { if (this.stream != null) { this.stream.flush(); } } } 

===========

  OkHttpClient client = new OkHttpClient.Builder() .addNetworkInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); if (originalRequest.body() == null) { return chain.proceed(originalRequest); } Request progressRequest = originalRequest.newBuilder() .method(originalRequest.method(), new UploadProgressRequestBody(originalRequest.body())) .build(); return chain.proceed(progressRequest); } }).build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build(); 
+1
source

All Articles