Tracking progress of multipart file upload using OKHTTP

后端 未结 3 1011
[愿得一人]
[愿得一人] 2020-11-30 18:19

I am trying to implement a a progress bar to indicate the progress of a multipart file upload.

I have read from a comment on this answer - https://stackoverflow.com/

相关标签:
3条回答
  • 2020-11-30 18:55

    This thing works great!

    Gradle

    dependencies {
      compile 'io.github.lizhangqu:coreprogress:1.0.2'
    }
    
    //wrap your original request body with progress
    RequestBody requestBody = ProgressHelper.withProgress(body, new ProgressUIListener()....} 
    

    Full example code here https://github.com/lizhangqu/CoreProgress

    0 讨论(0)
  • 2020-11-30 19:00

    You have to create a custom RequestBody and override writeTo method, and there you have to send your files down the sink in segments. It is very important that you flush the sink after each segment, otherwise your progress bar will fill up quickly without the file being actually sent over the network, because the contents will stay in the sink (which acts like a buffer).

    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);
        }
    
    }
    

    You can find a complete implementation that supports displaying progress in an AdapterView and also cancelling uploads at my gist: https://gist.github.com/eduardb/dd2dc530afd37108e1ac

    0 讨论(0)
  • 2020-11-30 19:02
    • We just need to create a custom RequestBody, no need to implement custom BufferedSink. We can allocate Okio buffer to read from image file, and connect this buffer to sink.

    For an example, please see the below createCustomRequestBody function

    public static RequestBody createCustomRequestBody(final MediaType contentType, final File file) {
        return new RequestBody() {
            @Override public MediaType contentType() {
                return contentType;
            }
            @Override public long contentLength() {
                return file.length();
            }
            @Override public void writeTo(BufferedSink sink) throws IOException {
                Source source = null;
                try {
                    source = Okio.source(file);
                    //sink.writeAll(source);
                    Buffer buf = new Buffer();
                    Long remaining = contentLength();
                    for (long readCount; (readCount = source.read(buf, 2048)) != -1; ) {
                        sink.write(buf, readCount);
                        Log.d(TAG, "source size: " + contentLength() + " remaining bytes: " + (remaining -= readCount));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }
    
    • to use -

      .addPart(
          Headers.of("Content-Disposition", "form-data; name=\"image\""),
          createCustomRequestBody(MediaType.parse("image/png"), new File("test.jpg")))
      .build()
      
    0 讨论(0)
提交回复
热议问题