send Downloader progress on a 100 ms timer

No need to flood receivers with progress events since they are basically
always going to the UI, and the UI will only refresh every so often.  If
the refresh rate is 50Hz, then that's every 20ms.  100ms seems to make a
smooth enough progress bar, and saves some CPU time.  This becomes more
important if there are multiple downloads happening in the background, like
if we make DownloaderService support parallel downloads from different repos
This commit is contained in:
Hans-Christoph Steiner 2016-04-05 11:08:11 +02:00
parent 5e59f812ce
commit fc9459d6c5

View File

@ -10,6 +10,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;
public abstract class Downloader {
@ -25,6 +27,9 @@ public abstract class Downloader {
public static final String EXTRA_TOTAL_BYTES = "org.fdroid.fdroid.net.Downloader.extra.TOTAL_BYTES";
private volatile boolean cancelled = false;
private volatile int bytesRead;
private volatile int totalBytes;
private Timer timer;
private final OutputStream outputStream;
@ -42,6 +47,9 @@ public abstract class Downloader {
void sendProgress(URL sourceUrl, int bytesRead, int totalBytes);
}
/**
* For sending download progress, should only be called in {@link #progressTask}
*/
private DownloaderProgressListener downloaderProgressListener;
protected abstract InputStream getDownloadersInputStream() throws IOException;
@ -123,6 +131,9 @@ public abstract class Downloader {
private void throwExceptionIfInterrupted() throws InterruptedException {
if (cancelled) {
Utils.debugLog(TAG, "Received interrupt, cancelling download");
if (timer != null) {
timer.cancel();
}
throw new InterruptedException();
}
}
@ -140,16 +151,17 @@ public abstract class Downloader {
* progress counter.
*/
private void copyInputToOutputStream(InputStream input, int bufferSize) throws IOException, InterruptedException {
int bytesRead = 0;
int totalBytes = totalDownloadSize();
bytesRead = 0;
totalBytes = totalDownloadSize();
byte[] buffer = new byte[bufferSize];
timer = new Timer();
timer.scheduleAtFixedRate(progressTask, 0, 100);
// Getting the total download size could potentially take time, depending on how
// it is implemented, so we may as well check this before we proceed.
throwExceptionIfInterrupted();
sendProgress(bytesRead, totalBytes);
while (true) {
int count;
@ -168,19 +180,25 @@ public abstract class Downloader {
}
bytesRead += count;
sendProgress(bytesRead, totalBytes);
outputStream.write(buffer, 0, count);
}
timer.cancel();
timer.purge();
outputStream.flush();
outputStream.close();
}
private void sendProgress(int bytesRead, int totalBytes) {
if (downloaderProgressListener != null) {
downloaderProgressListener.sendProgress(sourceUrl, bytesRead, totalBytes);
/**
* Send progress updates on a timer to avoid flooding receivers with pointless events.
*/
private final TimerTask progressTask = new TimerTask() {
@Override
public void run() {
if (downloaderProgressListener != null) {
downloaderProgressListener.sendProgress(sourceUrl, bytesRead, totalBytes);
}
}
}
};
/**
* Overrides every method in {@link InputStream} and delegates to the wrapped stream.