okhttp3 - 如何控制网络使用(上传限制)

时间:2016-07-12 13:32:51

标签: android throttling okhttp3

我正在尝试使用okhttp3库上传图像。

当上传开始时,okhttp会占用所有可用带宽,因此无法与我的应用或任何其他应用建立任何其他连接。

我的代码是:

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

1 个答案:

答案 0 :(得分:1)

您可以限制正在读取的缓冲区的速度。 例如,每上传24KB数据,我们就会休眠100ms。

这可以使用以下自定义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);
    }
}

像这样将ProgressRequestBody附加到您的请求:

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();