android - programacion - Seguimiento del progreso de la carga de archivos de varias partes mediante OKHTTP
manual android studio avanzado (3)
Estoy tratando de implementar una barra de progreso para indicar el progreso de una carga de archivos de varias partes.
He leído de un comentario sobre esta respuesta - https://stackoverflow.com/a/24285633/1022454 que tengo que envolver el receptor pasado a RequestBody y proporcionar una devolución de llamada que rastrea los bytes movidos.
Creé un RequestBody personalizado y envolví el receptor con una clase CustomSink; sin embargo, a través de la depuración puedo ver que RealBufferedSink ln 44 escribe los bytes y el método de escritura del receptor personalizado solo se ejecuta una vez, lo que no me permite rastrear los bytes movidos .
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();
}
}
¿Alguien tiene un ejemplo de cómo voy a hacer esto?
¡Esto funciona genial!
Gradle
dependencies {
compile ''io.github.lizhangqu:coreprogress:1.0.2''
}
//wrap your original request body with progress
RequestBody requestBody = ProgressHelper.withProgress(body, new ProgressUIListener()....}
El código de ejemplo completo aquí https://github.com/lizhangqu/CoreProgress
Tienes que crear un RequestBody personalizado y anular el método writeTo, y allí tienes que enviar tus archivos por el fregadero en segmentos. Es muy importante que descargue el fregadero después de cada segmento, de lo contrario, su barra de progreso se llenará rápidamente sin que el archivo se envíe realmente a través de la red, porque el contenido permanecerá en el fregadero (que actúa como un búfer).
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);
}
}
Puede encontrar una implementación completa que admita la visualización del progreso en un AdapterView y también la cancelación de cargas en mi esencia: https://gist.github.com/eduardb/dd2dc530afd37108e1ac
- Solo tenemos que crear un
RequestBody
personalizado, no es necesario implementar unBufferedSink
personalizado. Podemos asignar el búfer Okio para leer desde el archivo de imagen y conectar este búfer al receptor.
Para ver un ejemplo, consulte la siguiente función createCustomRequestBody
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();
}
}
};
}
usar -
.addPart( Headers.of("Content-Disposition", "form-data; name=/"image/""), createCustomRequestBody(MediaType.parse("image/png"), new File("test.jpg"))) .build()