OkHttp上传进度与实际上传不同步

时间:2016-07-12 10:14:19

标签: android file-upload okhttp3

我尝试使用OkHttp跟踪上传的进度。我创建了一个自定义class Pet: NSObject { var name : String? var birthYear : String? var birthMonth : String? var gender : String? var breed : String? } ,其中包含以下正文(由this answer提供),该正文写入接收器并发布进度。

RequestBody

这里的问题是,接收器被写入以立即接收,而不实际将缓冲的字节发送到服务器。这意味着我的进度在实际上传之前很久就会结束 注意: Some say接收器需要在每次迭代时刷新,以便实际上传字节,但它对我不起作用。

2 个答案:

答案 0 :(得分:1)

我知道这是一篇旧帖子,但对于有同样问题的人,我从这个lib中调整了一个帮助类(ProgressOutputStream):https://github.com/lizhangqu/CoreProgress我的工作代码如下:(用于上传文件和也可以上传json)

   {
  "data":{
    "fieldA":"A",
    "fieldB" : "B",
    "fieldC" : "C",
    "total" : 1234,
    "title" : "_my_title",
    "message" : "_my_message",
    "sound" : "default",
    "cick_action": "FCM_PLUGIN_ACTIVITY"
  },
    "to":"/topics/MY_TOPIC",
    "priority":"high"
}

===========

import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.BufferedSink;
import okio.Okio;

public class UploadProgressRequestBody extends RequestBody {
    private final RequestBody requestBody;
    private final ProgressListener progressListener;

    public UploadProgressRequestBody(RequestBody requestBody) {
        this.requestBody = requestBody;
        this.progressListener = getDefaultProgressListener();
    }

    @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 {
        if (progressListener == null) {
            requestBody.writeTo(sink);
            return;
        }
        ProgressOutputStream progressOutputStream = new ProgressOutputStream(sink.outputStream(), progressListener, contentLength());
        BufferedSink progressSink = Okio.buffer(Okio.sink(progressOutputStream));
        requestBody.writeTo(progressSink);
        progressSink.flush();
    }

    interface ProgressListener {
        void update(long bytesWritten, long contentLength);
    }

    private ProgressListener getDefaultProgressListener(){
        ProgressListener progressListener = new UploadProgressRequestBody.ProgressListener() {
            @Override public void update(long bytesRead, long contentLength) {
                System.out.println("bytesRead: "+bytesRead);
                System.out.println("contentLength: "+contentLength);
                System.out.format("%d%% done\n", (100 * bytesRead) / contentLength);
            }
        };

        return progressListener;
    }

}

==========

import java.io.IOException;
import java.io.OutputStream;

class ProgressOutputStream extends OutputStream {
    private final OutputStream stream;
    private final UploadProgressRequestBody.ProgressListener listener;

    private long total;
    private long totalWritten;

    ProgressOutputStream(OutputStream stream, UploadProgressRequestBody.ProgressListener listener, long total) {
        this.stream = stream;
        this.listener = listener;
        this.total = total;
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        this.stream.write(b, off, len);
        if (this.total < 0) {
            this.listener.update(-1, -1);
            return;
        }
        if (len < b.length) {
            this.totalWritten += len;
        } else {
            this.totalWritten += b.length;
        }
        this.listener.update(this.totalWritten, this.total);
    }

    @Override
    public void write(int b) throws IOException {
        this.stream.write(b);
        if (this.total < 0) {
            this.listener.update(-1, -1);
            return;
        }
        this.totalWritten++;
        this.listener.update(this.totalWritten, this.total);
    }

    @Override
    public void close() throws IOException {
        if (this.stream != null) {
            this.stream.close();
        }
    }

    @Override
    public void flush() throws IOException {
        if (this.stream != null) {
            this.stream.flush();
        }
    }
}

答案 1 :(得分:1)

经过辛苦的一天的挖掘,我发现了这个天才的解决方案,可以在网络接口级别设置缓冲区大小。我的问题是进度正在立即(眨眼)跳到一半以上。原来,正在读取我的输入流,并且正在写入缓冲区(输出流),直到系统确定足够,消耗掉它然后继续进行操作。这使得无法准确跟踪上载进度。看一看: Fix for upload progress monitoring in Android.

尝试该类,并将其sendBufferSize设置为较小但合理的值或证明合适的值。

int sendBufferSize = 128 * 1028;
new OkHttpClient.Builder().socketFactory(new RestrictedSocketFactory(sendBufferSize));

关于进度跃升至100的问题的注释:我遇到了很多答案,表明这是由于OkHttp日志记录所致。尝试将其关闭,看看是否有帮助。