Ось як обробляти хід завантаження файлів за допомогою простого POST, а не Multipart. Для отримання деталей ознайомтесь із рішенням @ Yariy. Крім того, це рішення використовує URI вмісту замість прямих посилань на файли.
RestClient
@Headers({
"Accept: application/json",
"Content-Type: application/octet-stream"
})
@POST("api/v1/upload")
Call<FileDTO> uploadFile(@Body RequestBody file);
ProgressRequestBody
public class ProgressRequestBody extends RequestBody {
private static final String LOG_TAG = ProgressRequestBody.class.getSimpleName();
public interface ProgressCallback {
public void onProgress(long progress, long total);
}
public static class UploadInfo {
public Uri contentUri;
public long contentLength;
}
private WeakReference<Context> mContextRef;
private UploadInfo mUploadInfo;
private ProgressCallback mListener;
private static final int UPLOAD_PROGRESS_BUFFER_SIZE = 8192;
public ProgressRequestBody(Context context, UploadInfo uploadInfo, ProgressCallback listener) {
mContextRef = new WeakReference<>(context);
mUploadInfo = uploadInfo;
mListener = listener;
}
@Override
public MediaType contentType() {
return MediaType.parse("application/octet-stream");
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
long fileLength = mUploadInfo.contentLength;
byte[] buffer = new byte[UPLOAD_PROGRESS_BUFFER_SIZE];
InputStream in = in();
long uploaded = 0;
try {
int read;
while ((read = in.read(buffer)) != -1) {
mListener.onProgress(uploaded, fileLength);
uploaded += read;
sink.write(buffer, 0, read);
}
} finally {
in.close();
}
}
@Override
public long contentLength() throws IOException {
return mUploadInfo.contentLength;
}
private InputStream in() throws IOException {
InputStream stream = null;
try {
stream = getContentResolver().openInputStream(mUploadInfo.contentUri);
} catch (Exception ex) {
Log.e(LOG_TAG, "Error getting input stream for upload", ex);
}
return stream;
}
private ContentResolver getContentResolver() {
if (mContextRef.get() != null) {
return mContextRef.get().getContentResolver();
}
return null;
}
}
Щоб розпочати завантаження:
ProgressRequestBody requestBody = new ProgressRequestBody(
getContext(),
new UploadInfo(myUri, fileSize),
new ProgressRequestBody.ProgressCallback() {
public void onProgress(long progress, long total) {
}
}
);
mRestClient.uploadFile(requestBody);
Попередження, якщо ви забудете замінити функцію contentLength (), ви можете отримати кілька неясних помилок:
retrofit2.adapter.rxjava.HttpException: HTTP 503 client read error
Або
Write error: ssl=0xb7e83110: I/O error during system call, Broken pipe
Або
javax.net.ssl.SSLException: Read error: ssl=0x9524b800: I/O error during system call, Connection reset by peer
Вони є результатом багаторазового виклику RequestBody.writeTo (), оскільки за замовчуванням contentLength () дорівнює -1.
У будь-якому випадку це довго затягувалось, сподіваюся, що це допоможе.
Корисні посилання:
https://github.com/square/retrofit/issues/1217