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

标签 android throttling okhttp

我正在尝试使用 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

最佳答案

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

这可以使用这个自定义的 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();

关于android - okhttp3 - 如何控制网络使用(上传 throttle ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38330391/

相关文章:

java - Android Maven 无法解析配置的依赖关系

php - pdo连接在php函数中不起作用

android - 如何在Android中按@键打开对话框窗口?

Android 映射异常 java.lang.NoClassDefFoundError : android. security.MessageDigest

python - 在 Python Asyncio 中限制异步函数

java - Okhttp3 - 调用 API 后出现 IndexOutOfBoundsException

java - VPN 开启时无法访问 REST 端点

android - okhttp 和 httpurlconnection 的区别?

android - 如何在 Android 中设置到期日期

c++ - 减少线程或进程的 CPU 使用率