Android OkHttp 请求进度

在 Android 开发中,我们经常需要通过网络请求获取数据。而使用 OkHttp 这个流行的 HTTP 客户端库可以帮助我们更方便地进行网络请求。在某些情况下,我们可能需要了解请求的进度,例如上传或下载大文件时。本文将介绍如何使用 OkHttp 实现请求进度的监控。

OkHttp 简介

OkHttp 是一个开源的 HTTP 客户端库,由 Square 公司开发。它提供了简洁的 API,支持同步和异步请求,并支持连接池、GZIP 压缩、缓存等功能。由于其简单易用和性能优越,OkHttp 在 Android 中被广泛应用。

请求进度的监控

OkHttp 提供了一个 Interceptor 接口,可以用于监控请求和响应。我们可以通过实现该接口来监控请求的进度,并在适当的时候更新进度条或显示进度信息。

监控上传进度

当我们需要上传一个大文件时,我们可以通过实现 Interceptor 接口来监控上传的进度。

以下是一个示例代码:

public class ProgressRequestBody extends RequestBody {
    private static final int DEFAULT_BUFFER_SIZE = 2048;

    private final File file;
    private final ProgressListener listener;

    public ProgressRequestBody(File file, ProgressListener listener) {
        this.file = file;
        this.listener = listener;
    }

    @Override
    public MediaType contentType() {
        return MediaType.parse("application/octet-stream");
    }

    @Override
    public long contentLength() {
        return file.length();
    }

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        try (Source source = Okio.source(file)) {
            Buffer buffer = new Buffer();
            long total = 0;
            long read;
            while ((read = source.read(buffer, DEFAULT_BUFFER_SIZE)) != -1) {
                sink.write(buffer, read);
                total += read;
                listener.onProgress(total, contentLength());
            }
        }
    }

    public interface ProgressListener {
        void onProgress(long progress, long total);
    }
}

在这个示例中,我们自定义了一个 ProgressRequestBody 类,继承自 OkHttp 的 RequestBody 类。该类负责将文件内容写入请求的 BufferedSink,并在每次写入后回调进度监听器。

为了实现进度监听,我们定义了一个接口 ProgressListener,其中的 onProgress 方法用于接收进度信息。

要创建一个带有进度监听的请求,我们只需要使用 ProgressRequestBody 替代原来的 RequestBody,并在构造函数中传入进度监听器。

以下是一个示例代码,展示了如何使用 ProgressRequestBody 发起一个上传请求:

OkHttpClient client = new OkHttpClient.Builder()
        .addNetworkInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request originalRequest = chain.request();
                Request progressRequest = originalRequest.newBuilder()
                        .method(originalRequest.method(),
                                new ProgressRequestBody(file, new ProgressRequestBody.ProgressListener() {
                                    @Override
                                    public void onProgress(long progress, long total) {
                                        // 更新进度条或显示进度信息
                                    }
                                }))
                        .build();
                return chain.proceed(progressRequest);
            }
        })
        .build();

Request request = new Request.Builder()
        .url("
        .post(RequestBody.create(MediaType.parse("application/octet-stream"), file))
        .build();

Response response = client.newCall(request).execute();

在这个示例中,我们创建了一个新的 OkHttpClient 实例,并添加了一个 Interceptor 来监控上传进度。在 Interceptor 中,我们将原始请求替换为一个新的请求,其中包含了一个 ProgressRequestBody

监控下载进度

如果我们需要下载一个大文件,我们可以通过实现 ResponseBody 来监控下载的进度。

以下是一个示例代码:

public class ProgressResponseBody extends ResponseBody {
    private final ResponseBody responseBody;
    private final ProgressListener listener;

    private BufferedSource bufferedSource;

    public ProgressResponseBody(ResponseBody responseBody, ProgressListener listener) {
        this.responseBody = responseBody;
        this.listener = listener;
    }

    @Override
    public MediaType contentType() {
        return responseBody.contentType();
    }

    @Override
    public long contentLength() {
        return responseBody.contentLength();
    }

    @Override
    public BufferedSource source() {
        if (bufferedSource == null) {
            bufferedSource = Okio.buffer(source(responseBody.source()));