Skip to content

Instantly share code, notes, and snippets.

@kyawkyaw
Created December 18, 2015 09:00
Show Gist options
  • Save kyawkyaw/54d9e2feb1c969c90673 to your computer and use it in GitHub Desktop.
Save kyawkyaw/54d9e2feb1c969c90673 to your computer and use it in GitHub Desktop.
How to track the progress of any OkHttp request body. Licence: MIT

How to track the progress of any OkHttp request body

Requires OkHttp >= 2.1.0 if you need to work with multipart request bodies. Lower versions don’t report the content length for the body, but the sum of the sizes of the parts is a pretty good approximation.

// TODO: Build a request body
RequestBody body = null;

// Decorate the request body to keep track of the upload progress
CountingRequestBody countingBody = new CountingRequestBody(body,
        new CountingRequestBody.Listener() {

    @Override
    public void onRequestProgress(long bytesWritten, long contentLength) {
        float percentage = 100f * bytesWritten / contentLength;
        // TODO: Do something useful with the values
    }
});

// TODO: Build a request using the decorated body
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.RequestBody;
import java.io.IOException;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
/**
* Decorates an OkHttp request body to count the number of bytes written when writing it. Can
* decorate any request body, but is most useful for tracking the upload progress of large
* multipart requests.
*
* @author Leo Nikkilä
*/
public class CountingRequestBody extends RequestBody {
protected RequestBody delegate;
protected Listener listener;
protected CountingSink countingSink;
public CountingRequestBody(RequestBody delegate, Listener listener) {
this.delegate = delegate;
this.listener = listener;
}
@Override
public MediaType contentType() {
return delegate.contentType();
}
@Override
public long contentLength() {
return delegate.contentLength();
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
BufferedSink bufferedSink;
countingSink = new CountingSink(sink);
bufferedSink = Okio.buffer(countingSink);
delegate.writeTo(bufferedSink);
bufferedSink.flush();
}
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 {
super.write(source, byteCount);
bytesWritten += byteCount;
listener.onRequestProgress(bytesWritten, contentLength());
}
}
public static interface Listener {
public void onRequestProgress(long bytesWritten, long contentLength);
}
}
@BytesZero
Copy link

Good

@mufumbo
Copy link

mufumbo commented Jun 13, 2018

hey, do you think it's possible to reuse the bufferedSink so we don't allocate a lot of these through the upload process?

@NLLAPPS
Copy link

NLLAPPS commented Apr 7, 2019

How would one set read size with this? I am trying to increase size of the data posted. For example something like this https://gist.github.com/verygreenboi/3c7c78d7f9350c6287bd#file-countingfilerequestbody-java

@javieranton-zz
Copy link

javieranton-zz commented Aug 20, 2020

Tested this and saw it go from 0 to 100 but not stop anywhere in between
Edit: not using multipart. But the code says "any request body"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment