Last active
September 2, 2019 11:57
-
-
Save AniketSK/6a10d942fdcea2d5db4e0e7725538cfb to your computer and use it in GitHub Desktop.
A demonstration of how a speed calculation could be done from the OnProgressListener of https://github.com/MindorksOpenSource/PRDownloader Here's how it works: 1. To make an accurate estimate of the speed, you need a certain number of progress updates, you can choose what number this is. 2. If we haven't reached that number of observations, retu…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.downloader | |
import org.junit.Test | |
import java.util.* | |
import java.util.concurrent.TimeUnit | |
class OnProgressSpeedListenerTest { | |
@Test | |
fun `speed is not calculated until the required number of samples have been received`() { | |
var speed : Long? = null | |
val speedCalc = DownloadSpeedCalculator(2, onSpeedUpdated = { s -> speed = s }) | |
val times = 1 | |
repeat(times) { i -> speedCalc.onProgress(TimeStampedProgress(i * 500L, Progress(i * 1000L, times * 10000L))) } | |
assert(speed == null) | |
} | |
@Test | |
fun `speed is calculated correctly`() { | |
var speed : Long? = 0L | |
val speedCalc = DownloadSpeedCalculator(2, onSpeedUpdated = { s -> speed = s }) | |
val times = 2 | |
repeat(times) { i -> speedCalc.onProgress(TimeStampedProgress(i * 500L, Progress(i * 1000L, times * 10000L))) } | |
assert(speed == 2L) | |
} | |
} | |
class DownloadSpeedCalculator(private val maxElements: Int = 2, private val onSpeedUpdated : (Long?) -> (Unit) ) : TimeStampedProgressListener(2, TimeUnit.SECONDS) { | |
private val allProgressEvents = ArrayDeque<TimeStampedProgress>(maxElements) | |
override fun onProgress(timeStampedProgress: TimeStampedProgress) { | |
allProgressEvents.apply { | |
push(timeStampedProgress) | |
if (size > maxElements) { | |
removeLast() | |
} | |
} | |
onSpeedUpdated(getAverageSpeedBytesPerMillisecond()) | |
} | |
/** | |
* Returns the current speed if it has received the specified minimum number of Progress values to | |
* make a reasonable speed determination, | |
* or null if enough Progress values have not yet been received. | |
*/ | |
private fun getAverageSpeedBytesPerMillisecond(): Long? = allProgressEvents.takeIf { | |
it.size == maxElements | |
}?.let { | |
Total(allProgressEvents.last.progress.currentBytes - allProgressEvents.first.progress.currentBytes, | |
allProgressEvents.first.lastTimeStamp, allProgressEvents.last.lastTimeStamp).getAverageSpeed() | |
} | |
private data class Total( | |
val totalBytes: Long = 0, | |
val startTime: Long = 0, | |
val endTime: Long = 0 | |
) { | |
fun getAverageSpeed() = totalBytes / (endTime - startTime) | |
} | |
} | |
abstract class TimeStampedProgressListener(updateInterval: Long, updateIntervalUnit: TimeUnit) : OnProgressListener { | |
private val INITIAL = 0L | |
private val intervalMillis = TimeUnit.MILLISECONDS.convert(updateInterval, updateIntervalUnit) | |
private var lastUpdateTime: Long = INITIAL | |
final override fun onProgress(progress: Progress?) { | |
defaultConditionalProgress(progress) | |
} | |
private fun defaultConditionalProgress(progress: Progress?) { | |
if (progress == null) | |
return | |
val now = now() | |
if (now - lastUpdateTime >= intervalMillis) { | |
lastUpdateTime = now | |
onProgress(TimeStampedProgress(now, progress)) | |
} | |
} | |
abstract fun onProgress(progress: TimeStampedProgress) | |
private fun now(): Long = System.currentTimeMillis() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A demonstration of how a speed calculation could be done from the OnProgressListener of https://github.com/MindorksOpenSource/PRDownloader
Here's how it works:
This gives you average of bytes/millisecond, over that interval.
This is a junit test, to actually use it, you'd take the classes in it and put them in separate files, then create a subclass of DownloadSpeedQueue as an OnProgressListener, pass the time intervals you'd like to measure in, and the onSpeedUpdated function.
onSpeedUpdated will receive bytes per millisecond when it's calculated.