Android Retrofit - Onprogressupdate for Showing Progress Notification

Android Retrofit - onProgressUpdate for showing Progress Notification

This answer is for Retrofit 1. For solution compatible with Retrofit 2 see this answer.


I had the same problem and finally managed to do it. I was using spring lib before and what I show below kind worked for Spring but was inconsistent since I made a mistake on using it for the InputStream. I moved all my API's to use retrofit and upload was the last one on the list, I just override TypedFile writeTo() to update me on the bytes read to the OutputStream. Maybe this can be improved but as I said I made it when I was using Spring so I just reused it.
This is the code for upload and it's working for me on my app, if you want download feedback then you can use @Streaming and read the inputStream.

ProgressListener

public interface ProgressListener {
void transferred(long num);
}

CountingTypedFile

public class CountingTypedFile extends TypedFile {

private static final int BUFFER_SIZE = 4096;

private final ProgressListener listener;

public CountingTypedFile(String mimeType, File file, ProgressListener listener) {
super(mimeType, file);
this.listener = listener;
}

@Override public void writeTo(OutputStream out) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
FileInputStream in = new FileInputStream(super.file());
long total = 0;
try {
int read;
while ((read = in.read(buffer)) != -1) {
total += read;
this.listener.transferred(total);
out.write(buffer, 0, read);
}
} finally {
in.close();
}
}
}

MyApiService

public interface MyApiService {
@Multipart
@POST("/files")
ApiResult uploadFile(@Part("file") TypedFile resource, @Query("path") String path);
}

SendFileTask

private class SendFileTask extends AsyncTask<String, Integer, ApiResult> {
private ProgressListener listener;
private String filePath;
private FileType fileType;

public SendFileTask(String filePath, FileType fileType) {
this.filePath = filePath;
this.fileType = fileType;
}

@Override
protected ApiResult doInBackground(String... params) {
File file = new File(filePath);
totalSize = file.length();
Logger.d("Upload FileSize[%d]", totalSize);
listener = new ProgressListener() {
@Override
public void transferred(long num) {
publishProgress((int) ((num / (float) totalSize) * 100));
}
};
String _fileType = FileType.VIDEO.equals(fileType) ? "video/mp4" : (FileType.IMAGE.equals(fileType) ? "image/jpeg" : "*/*");
return MyRestAdapter.getService().uploadFile(new CountingTypedFile(_fileType, file, listener), "/Mobile Uploads");
}

@Override
protected void onProgressUpdate(Integer... values) {
Logger.d(String.format("progress[%d]", values[0]));
//do something with values[0], its the percentage so you can easily do
//progressBar.setProgress(values[0]);
}
}

The CountingTypedFile is just a copy of TypedFile but including the ProgressListener.

Is it possible to show progress bar when download file via Retrofit 2, Android

You can use ResponseBody and set it to OkHttp client and to update progress in UI you can use interface.check this link

Is it possible to show progress bar when upload image via Retrofit 2?

First of all, you should use Retrofit 2 version equal to or above 2.0 beta2.
Second, create new class extends RequestBody:

public class ProgressRequestBody extends RequestBody {
private File mFile;
private String mPath;
private UploadCallbacks mListener;
private String content_type;

private static final int DEFAULT_BUFFER_SIZE = 2048;

public interface UploadCallbacks {
void onProgressUpdate(int percentage);
void onError();
void onFinish();
}

Take note, I added content type so it can accommodate other types aside image

public ProgressRequestBody(final File file, String content_type,  final  UploadCallbacks listener) {
this.content_type = content_type;
mFile = file;
mListener = listener;
}

@Override
public MediaType contentType() {
return MediaType.parse(content_type+"/*");
}

@Override
public long contentLength() throws IOException {
return mFile.length();
}

@Override
public void writeTo(BufferedSink sink) throws IOException {
long fileLength = mFile.length();
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
FileInputStream in = new FileInputStream(mFile);
long uploaded = 0;

try {
int read;
Handler handler = new Handler(Looper.getMainLooper());
while ((read = in.read(buffer)) != -1) {

// update progress on UI thread
handler.post(new ProgressUpdater(uploaded, fileLength));

uploaded += read;
sink.write(buffer, 0, read);
}
} finally {
in.close();
}
}

private class ProgressUpdater implements Runnable {
private long mUploaded;
private long mTotal;
public ProgressUpdater(long uploaded, long total) {
mUploaded = uploaded;
mTotal = total;
}

@Override
public void run() {
mListener.onProgressUpdate((int)(100 * mUploaded / mTotal));
}
}
}

Third, create the interface

@Multipart
@POST("/upload")
Call<JsonObject> uploadImage(@Part MultipartBody.Part file);

/* JsonObject above can be replace with you own model, just want to
make this notable. */

Now you can get progress of your upload.
In your activity (or fragment):

class MyActivity extends AppCompatActivity implements ProgressRequestBody.UploadCallbacks {

ProgressBar progressBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

progressBar = findViewById(R.id.progressBar);

ProgressRequestBody fileBody = new ProgressRequestBody(file, this);
MultipartBody.Part filePart =

MultipartBody.Part.createFormData("image", file.getName(), fileBody);

Call<JsonObject> request = RetrofitClient.uploadImage(filepart);

request.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if(response.isSuccessful()){
/* Here we can equally assume the file has been downloaded successfully because for some reasons the onFinish method might not be called, I have tested it myself and it really not consistent, but the onProgressUpdate is efficient and we can use that to update our progress on the UIThread, and we can then set our progress to 100% right here because the file already downloaded finish. */
}
}

@Override
public void onFailure(Call<JsonObject> call, Throwable t) {
/* we can also stop our progress update here, although I have not check if the onError is being called when the file could not be downloaded, so I will just use this as a backup plan just in case the onError did not get called. So I can stop the progress right here. */
}
});

}

@Override
public void onProgressUpdate(int percentage) {
// set current progress
progressBar.setProgress(percentage);
}

@Override
public void onError() {
// do something on error
}

@Override
public void onFinish() {
// do something on upload finished,
// for example, start next uploading at a queue
progressBar.setProgress(100);
}

}

Android progressBar doesn't set progress after call Retrofit

You're attempting to change View from another thread. Check this question How to set text of text view in another thread

Basically, change:

 d.setProgress(progress);

to

d.post(new Runnable() {
public void run() {
d.setProgress(progress);
}
}


Related Topics



Leave a reply



Submit