当前位置: 首页 > 知识库问答 >
问题:

利用OKHTTP跟踪多部分文件上传的进度

蒋俊人
2023-03-14

我试图实现一个进度条来指示一个多部分文件上传的进度。

    private class CustomRequestBody extends RequestBody {

    MediaType contentType;
    byte[] content;

    private CustomRequestBody(final MediaType contentType, final byte[] content) {
        this.contentType = contentType;
        this.content = content;
    }

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

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

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        CustomSink customSink = new CustomSink(sink);
        customSink.write(content);

    }
}


private class CustomSink implements BufferedSink {

    private static final String TAG = "CUSTOM_SINK";

    BufferedSink bufferedSink;

    private CustomSink(BufferedSink bufferedSink) {
        this.bufferedSink = bufferedSink;
    }

    @Override
    public void write(Buffer source, long byteCount) throws IOException {
        Log.d(TAG, "source size: " + source.size() + " bytecount" + byteCount);
        bufferedSink.write(source, byteCount);
    }

    @Override
    public void flush() throws IOException {
        bufferedSink.flush();
    }

    @Override
    public Timeout timeout() {
        return bufferedSink.timeout();
    }

    @Override
    public void close() throws IOException {
        bufferedSink.close();
    }

    @Override
    public Buffer buffer() {
        return bufferedSink.buffer();
    }

    @Override
    public BufferedSink write(ByteString byteString) throws IOException {
        return bufferedSink.write(byteString);
    }

    @Override
    public BufferedSink write(byte[] source) throws IOException {
        return bufferedSink.write(source);
    }

    @Override
    public BufferedSink write(byte[] source, int offset, int byteCount) throws IOException {
        return bufferedSink.write(source, offset, byteCount);
    }

    @Override
    public long writeAll(Source source) throws IOException {
        return bufferedSink.writeAll(source);
    }

    @Override
    public BufferedSink writeUtf8(String string) throws IOException {
        return bufferedSink.writeUtf8(string);
    }

    @Override
    public BufferedSink writeString(String string, Charset charset) throws IOException {
        return bufferedSink.writeString(string, charset);
    }

    @Override
    public BufferedSink writeByte(int b) throws IOException {
        return bufferedSink.writeByte(b);
    }

    @Override
    public BufferedSink writeShort(int s) throws IOException {
        return bufferedSink.writeShort(s);
    }

    @Override
    public BufferedSink writeShortLe(int s) throws IOException {
        return bufferedSink.writeShortLe(s);
    }

    @Override
    public BufferedSink writeInt(int i) throws IOException {
        return bufferedSink.writeInt(i);
    }

    @Override
    public BufferedSink writeIntLe(int i) throws IOException {
        return bufferedSink.writeIntLe(i);
    }

    @Override
    public BufferedSink writeLong(long v) throws IOException {
        return bufferedSink.writeLong(v);
    }

    @Override
    public BufferedSink writeLongLe(long v) throws IOException {
        return bufferedSink.writeLongLe(v);
    }

    @Override
    public BufferedSink emitCompleteSegments() throws IOException {
        return bufferedSink.emitCompleteSegments();
    }

    @Override
    public OutputStream outputStream() {
        return bufferedSink.outputStream();
    }
}

有人能举个例子说明我会怎么做吗?

共有1个答案

岑畅
2023-03-14

您必须创建一个自定义的RequestBody并重写writeTo方法,在那里您必须将文件按段发送到接收器。在每个段之后刷新接收器是非常重要的,否则进度条将很快填满,而文件实际上不会通过网络发送,因为内容将留在接收器中(接收器的作用类似于缓冲区)。

public class CountingFileRequestBody extends RequestBody {

    private static final int SEGMENT_SIZE = 2048; // okio.Segment.SIZE

    private final File file;
    private final ProgressListener listener;
    private final String contentType;

    public CountingFileRequestBody(File file, String contentType, ProgressListener listener) {
        this.file = file;
        this.contentType = contentType;
        this.listener = listener;
    }

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

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

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        Source source = null;
        try {
            source = Okio.source(file);
            long total = 0;
            long read;

            while ((read = source.read(sink.buffer(), SEGMENT_SIZE)) != -1) {
                total += read;
                sink.flush();
                this.listener.transferred(total);

            }
        } finally {
            Util.closeQuietly(source);
        }
    }

    public interface ProgressListener {
        void transferred(long num);
    }

}

您可以在my Gist:https://gist.github.com/eduardb/dd2dc530afd37108e1ac找到一个支持在AdapterView中显示进度和取消上传的完整实现

 类似资料:
  • 我正在使用这个音频记录和视频文件,它是工作的,但我想用OKHTTP取代它。我没弄明白。有人能帮我一下吗?

  • 在Android中使用OKHTTP以多部分方式上传单个大文件(更具体地说,上传到s3)时,我有什么选择?

  • 由邮递员生成以下代码: 此请求在服务器上生成一个大小为0 Kb的文件。而且我无法放文件。所以,我必须放一个这样的文件: 但我有一个超时选项。 如何使用这种Rest API放置文件?

  • 它应该很简单:我必须发送文件和一些字符串值。但我想不出怎么做。 根据我发现的一些样本,我首先尝试了以下内容: 它给我一个“400错误请求”错误。 我做错了什么? 编辑:顺便说一句,上面的“getfile()”返回一个File对象。其余的参数都是字符串和int。

  • 我正在Spring controller中努力实现多部分文件上传。我读过很多问题,谷歌,但似乎什么都不管用。 我明白了 我的BE控制器: FE,angularJS: HTML: 还有应用程序。属性包括: 更新: 当我按照@Byeon0gam的建议从我的控制器中删除@RequestParam时,我不再会遇到这个错误,但是我的文件在控制器中是空的。虽然在FE服务中,如我所见,它不是空的: