Reputation: 10609
I have a Fragment
with a RecyclerView
and the RecyclerView
's ViewHolder
is holding a ProgressBar
to show the progress of a downloading process.
public static class ViewHolder extends RecyclerView.ViewHolder {
....
private ProgressBar progressBar = null;
....
public ViewHolder(View itemView) {
super(itemView);
....
this.progressBar = (ProgressBar) itemView.findViewById(R.id.progessbar);
....
}
}
I created a callback for my Fragment
:
public interface CallbackItemChanged {
void onItemChanged(final int position);
}
And if it is called i do:
@Override
public void onItemChanged(final int position) {
this.adapter.notifyItemChanged(position);
}
And in my AsyncTask
:
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
this.entry.setProgress(progress[0]);
this.entry.setProgressString(progress[0] + "%");
this.callbackItemChanged.onItemChanged(this.entry.getPosition());
}
The progress is published successfully but the ui is lagging like hell but i dont know why? The onProgressUpdate
is running on the ui thread isnt it? I think it should be like that or am i wrong?
How can i get the ui smoothly working while updating the progressbar?
EDIT
@Override
protected String doInBackground(Void... params) {
this.inputStream = null;
this.outputStream = null;
this.connection = null;
File file = new File(this.entry.getPath(this.context));
File parent = file.getParentFile();
try {
parent.mkdirs();
file.createNewFile();
this.connection = (HttpsURLConnection) new URL(this.entry.getUrl()).openConnection();
this.connection.connect();
int fileLength = this.connection.getContentLength();
this.inputStream = this.connection.getInputStream();
this.outputStream = new FileOutputStream(file);
byte data[] = new byte[4096];
long progress = 0;
int count;
while ((count = this.inputStream.read(data)) != -1) {
if (this.isCancelled() || this.entry.isCancelled()) {
this.handleClose();
this.handleDelete();
return null;
}
if (fileLength > 0) {
this.publishProgress((int) ((progress +=count) * 100 / fileLength));
}
this.outputStream.write(data, 0, count);
}
} catch (Exception e) {
this.handleDelete();
return e.toString();
} finally {
this.handleClose();
}
return null;
}
Upvotes: 0
Views: 1417
Reputation: 1409
You're publishing the progress inside a loop, so your main thread will be called a lot of times.
You could delay the progress publishing with a simple Thread.sleep():
while ((count = this.inputStream.read(data)) != -1) {
if (this.isCancelled() || this.entry.isCancelled()) {
this.handleClose();
this.handleDelete();
return null;
}
// Write the data before publishing the progress
this.outputStream.write(data, 0, count);
try{
// Adjust this value. It shouldn't be too small.
Thread.sleep(100);
}catch (InterruptedException e){
// Nothing you can do here
}finally {
if (fileLength > 0) {
this.publishProgress((int) ((progress +=count) * 100 / fileLength));
}
}
}
Or you could publish only by increments of x%:
while ((count = this.inputStream.read(data)) != -1) {
if (this.isCancelled() || this.entry.isCancelled()) {
this.handleClose();
this.handleDelete();
return null;
}
// Write the data before publishing the progress
this.outputStream.write(data, 0, count);
if (fileLength > 0) {
currentProgress = ((progress += count) * 100 / fileLength);
// Publish only on increments of 1%
if (currentProgress >= previousProgress + 1) {
this.publishProgress(currentProgress);
previousProgress = currentProgress;
}
}
}
Upvotes: 1