我正在执行发布请求,将文件上传到我的api。我如何以某种方式表示用户知道应用程序在做什么的进度?如何将其链接到进度条或其他东西?
编辑:我正在使用翻新2
我们可以将拦截器添加到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示例。