3

I have this while loop downloading a file

while ((val = bis.read(buffer, 0, 1024)) > 0) {
   out.write(buffer, 0, val);
   fileSize -= val;
   if (fileSize < 1024) {
   val = (int) fileSize;
}

Trying to figure out how to show Mbit/s like many speed sites do.(link)
http://www.speedtest.net/ .

Would like the mesurment to stay inside the while loop but i have
seen examples using on-minute-threads firing but i dunno..

I dont know the amount of data, or the data is always 1024.
thats on of the problems i think
Any help is grate?

Erik
  • 5,039
  • 10
  • 63
  • 119

2 Answers2

8

I might be wrong by an order of magnitude or two, by the general idea is as follows:

long start = System.nanoTime();
long totalRead = 0;
final double NANOS_PER_SECOND = 1000000000.0;
final double BYTES_PER_MIB = 1024 * 1024;

while ((val = bis.read(buffer, 0, 1024)) > 0) {
    //...
    totalRead += val;
    double speedInMBps = NANOS_PER_SECOND / BYTES_PER_MIB * totalRead / (System.nanoTime() - start + 1);
    double speedInMbps = speed * 8;
}

Note that this calculates average speed from the beginning, not the current velocity.

Robert
  • 1,660
  • 22
  • 39
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • what about this, should i just set it to 1000. cannot convert from double to float. final float NANOS_PER_SECOND = 1000000000.0; – Erik Nov 16 '11 at 17:26
  • 1
    change all floats to doubles then – soulcheck Nov 16 '11 at 17:30
  • 2
    nice i get this 0.5683736337 Mbit/s output. Im running Android phone on my LAN wifi to my computer over FTP. Maybe that is approximately half-a-MegaBit speed. how to verify that this is correct – Erik Nov 16 '11 at 17:38
  • 2
    One correction, this program outputs mega**bytes** per second, so 0,5 is actually around 4 Mbit/s. – Tomasz Nurkiewicz Nov 16 '11 at 18:11
  • 1
    @Erik: Yes, 4.5 Mbit/s it is. – Tomasz Nurkiewicz Nov 16 '11 at 18:37
  • @Tomasz Nurkiewicz created a follow up question for anyone else doing this http://stackoverflow.com/questions/8157437/java-how-to-show-user-friendly-formatted-output-regarding-bandwidth-speed-during – Erik Nov 16 '11 at 22:09
  • @TomaszNurkiewicz Hey tomas could you explain the meaning of your constants ? For isntance what is BYTES_PER_MIB ?And why do you do NANOS_PER_SECOND / BYTES_PER_MIB ? And also Why "+1" at the end of the speed formula ? – tsukanomon May 23 '15 at 17:29
4

I'm assuming that this loop is not executing on the UI thread. Declare two instance variables in your class:

volatile long totalDownloaded;
long downloadStartTime;

Modify your loop code as follows:

totalDownloaded = 0L;
downloadStartTime = System.currentTimeMillis();
while ((val = bis.read(buffer, 0, 1024)) > 0) {
   out.write(buffer, 0, val);
   totalDownloaded += val;
   fileSize -= val;
   if (fileSize < 1024) {
   val = (int) fileSize;
}

Schedule a task to run on the UI thread every so often that computes System.currentTimeMillis() - downloadStartTime and uses the elapsed time and the then-current value of totalDownloaded to compute the average download speed and update the display. You can do all this in a separate method in the same class:

/**
 * Returns average download speed in bytes/second.
 */
public float getDownloadSpeed() {
    long elapsedTime = System.currentTimeMillis() - downloadStartTime;
    return 1000f * totalDownloaded / elapsedTime;
}
Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • maybe yea , btw everything is happening in an Android IntentService.class – Erik Nov 16 '11 at 17:21
  • @Erik - In order to interact with an activity, you might want to use a bound service instead of an IntentService. – Ted Hopp Nov 16 '11 at 17:55
  • the IntentService only display a Notification with Download progress in procent and now also with Mbit/s. – Erik Nov 16 '11 at 17:59
  • @TedHopp Hi, may I ask why do you multiply totalDownloaded by 1000? – phuwin Jul 13 '16 at 07:47
  • 1
    @PhuNguyen - That's because `elapsedTime` is in milliseconds and the return value should be in units of bytes/second. To convert milliseconds to seconds, one divides by 1000. But since `elapsedTime` is in the denominator, this is equivalent to multiplying the return value by 1000. It could have been written `return totalDownloaded / (elapsedTime / 1000f);`. – Ted Hopp Jul 13 '16 at 15:06
  • @TedHopp Thanks for your kind explanation. I had a mistake in converting milliseconds into seconds. – phuwin Jul 14 '16 at 07:01