Reputation: 183
I am trying to upload an image using okhttp3 library.
What happens is that, when the upload starts, the okhttp takes up all the available bandwidth making it impossible to make any other connection from my app or any other app.
My code is:
ProgressRequestBody fileBody = new ProgressRequestBody(
RequestBody.create(MediaType.parse(getMimeType(sourceFile)), sourceFile),
new ProgressRequestBody.Listener() {
@Override
public void onProgress(int progress) {
//update progress
}
});
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("key", key)
.addFormDataPart("file", sourceFile.getName(), fileBody)
.build();
Request request = new Request.Builder()
.url(Global.server_url + "upload")
.addHeader("authorization", Global.g_userInfo.getSessionId())
.post(requestBody)
.build();
Response response = okHttpClient.newCall(request).execute();
responseString = response.body().string();
statusCode = response.code();
Implementation of CountingRequestBody
Upvotes: 3
Views: 1047
Reputation: 393
You can throttle the speed of the buffer being read. For example, every 24KB uploaded we sleep for 100ms.
This can be implemented using this custom ProgressRequestBody:
public class ProgressRequestBody extends RequestBody {
protected final RequestBody requestBody;
protected final OnProgressListener listener;
protected ProgressForwardingSink progressForwardingSink;
public ProgressRequestBody(RequestBody requestBody, OnProgressListener listener) {
this.requestBody = requestBody;
this.listener = listener;
Timber.d("Throttle upload by adding %dms delay every %dKB", CHUNCK_DELAY, CHUNK_SIZE/1024);
}
@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 {
progressForwardingSink = new ProgressForwardingSink(sink);
BufferedSink bufferedSink = Okio.buffer(progressForwardingSink);
requestBody.writeTo(bufferedSink);
bufferedSink.flush();
}
protected final class ProgressForwardingSink extends ForwardingSink {
public final static int CHUNK_SIZE = 24 * 1024; // progress is updated every 8KB
public final static long CHUNCK_DELAY = 100;
private long bytesWritten = 0;
private long lastIndex = 0;
public ProgressForwardingSink(Sink delegate) {
super(delegate);
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWritten += byteCount;
long index = bytesWritten / CHUNK_SIZE;
Timber.d("bytesWritten %d index: %d lastIndex: %d", bytesWritten, index, lastIndex);
if (index > lastIndex) {
lastIndex = index;
try {
Timber.d("sleep %dms", CHUNCK_DELAY);
Thread.sleep(CHUNCK_DELAY);
} catch (InterruptedException e) {
Timber.d("chunk sleep interrupted");
}
}
listener.onRequestProgress(bytesWritten, contentLength());
}
}
public interface OnProgressListener {
void onRequestProgress(long bytesWritten, long contentLength);
}
}
And attaching the ProgressRequestBody to your Request like this:
ProgressRequestBody progressRequestBody = new ProgressRequestBody(requestBody, (bytesWritten, contentLength) -> {
int percent = Math.round(100 * ((float) bytesWritten) / ((float) contentLength));
Timber.d("upload progress: %d/%d %d%%", bytesWritten, contentLength, percent);
});
Request request = new Request.Builder()
.url(Global.server_url + "upload")
.addHeader("authorization", Global.g_userInfo.getSessionId())
.post(progressRequestBody)
.build();
Upvotes: 1