OKHTTP

2014-09-21 11 views
31

kullanarak çok parçalı dosya yükleme işleminin ilerleyişi Çok parçalı bir dosya yükleme işleminin ilerleyişini göstermek için bir ilerleme çubuğu uygulamaya çalışıyorum.OKHTTP

Bu yanıt hakkındaki bir yorumdan okudum - https://stackoverflow.com/a/24285633/1022454, RequestBody'ye geçirilen havuzu sarmam ve baytların taşınmasını sağlayan bir geri arama sağladım.

Özel bir RequestBody oluşturdum ve bir CustomSink sınıfı ile lavaboya sardım, ancak hata ayıklama yoluyla baytların RealBufferedSink ln 44 tarafından yazıldığını ve özel havuz yazma yönteminin yalnızca bir kez çalıştırıldığını görmüyorum; Byte taşınan baytları takip edin.

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

Bunu yapmak için nasıl gideceğime dair bir örneği var mı?

cevap

54

Özel bir RequestBody oluşturup WriteTo yöntemini geçersiz kılmak zorunda ve orada dosyalarınızı segmentteki lavaboya göndermelisiniz s. Her segmentten sonra lavabonu yıkamanız çok önemlidir. Aksi takdirde, ilerleme çubuğu, dosyanın ağ üzerinden gönderilmeden hızlı bir şekilde dolmasına neden olur, çünkü içeriğin havuzda kalması (tampon gibi davranır).

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

} 
Bir AdapterView ilerleme gösteren ve aynı zamanda benim ana fikri de yüklemeleri iptal destekleyen komple bir uygulama bulabilirsiniz

: https://gist.github.com/eduardb/dd2dc530afd37108e1ac

+0

Bu yavaş bir ağ bağlantısı üzerinden küçük dosya yükleme eğer çalışmak görünmüyor. Https://github.com/square/okhttp/issues/1078 adresine bakın. Bu dava için bir çözüm var mı? – coalmee

+0

@Edy Bolos RxJava & Observable ile birlikte kullanmanın bir yolu var mı? – Sree

+0

Sorunuzu cevaplamak için: her şey Gözlemlenebilir bir şekilde sarılabilir :) Ama bunu yapmak için başka birini bırakmak zorunda kalacağım. Tek önerim, 'UploadsHandler' –

10
  • Biz sadece özel bir RequestBody, özel BufferedSink uygulamak gerek oluşturmanız gerekir. Okio arabelleğini görüntü dosyasından okumak için ayırabiliriz ve bu arabelleği batağa bağlayabiliriz.
  • bir örnek için

aşağıya createCustomRequestBody fonksiyonunu bakın

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(); 
      } 
     } 
    }; 
} 
  • kullanmak -

    .addPart(
        Headers.of("Content-Disposition", "form-data; name=\"image\""), 
        createCustomRequestBody(MediaType.parse("image/png"), new File("test.jpg"))) 
    .build() 
    
1

Bu şey harika çalışıyor!

Gradle

dependencies { 
    compile 'io.github.lizhangqu:coreprogress:1.0.2' 
} 

//wrap your original request body with progress 
RequestBody requestBody = ProgressHelper.withProgress(body, new ProgressUIListener()....} 

için tam bir örnek kod burada https://github.com/lizhangqu/CoreProgress