如何在进度条(Android)中显示POST请求的进度?

问题描述 投票:0回答:1

我正在执行发布请求,将文件上传到我的api。我如何以某种方式表示用户知道应用程序在做什么的进度?如何将其链接到进度条或其他东西?

编辑:我正在使用翻新2

android request progress-bar
1个回答
0
投票

我们可以将拦截器添加到okhttp客户端以跟踪上传进度。

首先,您需要像这样扩展okhttp的ResponseBody类:

import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;

public class ProgressResponseBody extends ResponseBody {

    private final ResponseBody responseBody;
    private final ProgressListener progressListener;
    private BufferedSource bufferedSource;

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

    @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()));
        }
        return bufferedSource;
    }

    private Source source(Source source) {
        return new ForwardingSource(source) {
            long totalBytesRead = 0L;

            @Override
            public long read(Buffer sink, long byteCount) throws IOException {
                long bytesRead = super.read(sink, byteCount);
                // read() returns the number of bytes read, or -1 if this source is exhausted.
                totalBytesRead += bytesRead != -1 ? bytesRead : 0;
                progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
                return bytesRead;
            }
        };
    }
}

interface ProgressListener {
    void update(long bytesRead, long contentLength, boolean done);
}

此类负责跟踪进度并更新侦听器。

然后您必须创建一个新的侦听器实例:

final ProgressListener progressListener = new ProgressListener() {
      boolean firstUpdate = true;

      @Override public void update(long bytesRead, long contentLength, boolean done) {
        if (done) {
          System.out.println("completed");
        } else {
          if (firstUpdate) {
            firstUpdate = false;
            if (contentLength == -1) {
              System.out.println("content-length: unknown");
            } else {
              System.out.format("content-length: %d\n", contentLength);
            }
          }

          System.out.println(bytesRead);

          if (contentLength != -1) {
            System.out.format("%d%% done\n", (100 * bytesRead) / contentLength);
          }
        }
      }
    };

然后您必须将拦截器添加到okhttp客户端:

OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addNetworkInterceptor(chain -> {
          Response originalResponse = chain.proceed(chain.request());
          return originalResponse.newBuilder()
              .body(new ProgressResponseBody(originalResponse.body(), progressListener))
              .build();
        })
        .build();

最后,将新客户端添加到您的改造中:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("some url")
                .client(okHttpClient)
                .build();

[请注意,此方法跟踪所有API调用,而不仅仅是用于上传的特定API,要解决此问题,您可以将请求URL传递给ProgressListener.update(),然后可以使用EventBus发布包含URL的事件,并进度。

P.S。此方法基于官方的okhttp示例。

© www.soinside.com 2019 - 2024. All rights reserved.