CodeClash: Timer Implementations in Android

I’ve been an addict on looking for several ways to implement a concept, compare solutions, and do performance testing on solutions. In this episode of CodeClash (and it’s TV-ish to say), we’ll be comparing implementations of a countdown timer which is UI-visible in Android.

First stop, using a native java Thread

I just made this up (but working), with the help of a bit of research. I arrived with the solution thinking about implementing a timer in a J2SE platform. Instantiating a Thread with an anonymous function of type Runnable as its parameter. As a general practice sleep() method is called to stall before succeeding statements are ran.

		Thread k = new Thread(new Runnable() {
		    @Override
		    public void run() {
		        try {
		            for(itr=0 ; itr<1 ; itr++) {
		                Thread.sleep(1000);
		                runOnUiThread(new Runnable() {  
		                    @Override
		                    public void run() {
		                        tv.setText(itr+""); 
		                		Log.i("exec speed of Thread", System.currentTimeMillis()-startTime+"");
		                        return;
		                    }
		                });
		            }
		            return;
		             
		        } catch (InterruptedException e) {
		            // TODO Auto-generated catch block
		            e.printStackTrace();
		        }
		    }
		});
		 
		k.start();

It is not possible to access a View from a background process (our Thread) But with the use of the method runOnUiThread this would do the trick wrapping our setText method by a new Runnable.

To determine the execution speed we placed our indicators at the best positions. First, we declared our starting point before the instantiation of the Thread, and our end point after the TextView has been set that will indicate the end of the whole execution.

The Judgement

We are looking at 25 lines of code in this implementation and that for me would look lengthy for such simple feature. 2 anonymous functions have been declared which MAY be an efficiency concern for it may use more memory, and the way that it looks, it’s messy.

On the other hand, I see this code as flexible. We can have several commands before the sleep() if our intention requires such. Coding in a lowly level like this make it highly customizable.

Next Stop, using the CountDownTimer. It Exists!

		CountDownTimer timer = new CountDownTimer(1000, 1000) {
			 
		    public void onTick(long msNow) {
		        tv.setText("" + msNow / 1000);
		    }
		 
		    public void onFinish() {
		        tv.setText("00");
		    }
		 };
		  
		 timer.start();

I know you may be thinking, this is way simple than the other one. More readable, and reliable. Yes, it is. Implementing Timers using this class is the most widely used. It’s direct to the point which made it simple. The anonymous declaration contain 2 methods, onTick and onFinish. It is pretty much self explainable maybe. onTick is called every 1000 millisecond (as what is declared in the second parameter).

The Judgement

The highlight of this implemenation is its simplicity. Contains 12 lines of code, and is highly readable

On the other hand, we can only execute statements AFTER the tick, and none is allowed before the tick. Counted against writability but is not a serious issue for we can formulate workarounds to achieve that.

You may say that this only counts down, and doesn’t go up. It is plausible, and it’s up to your arithmetic skills.

The Rundown

Comparing execution times and memory usage

Implementation
Method
Run #1 Run #2 Run #3 Run #4 Run #5 Average
Thread 1123 ms
21704 bytes
1098 ms
13064 bytes
1097 ms
12592 bytes
1126 ms
12584 bytes
1114 ms
12432 bytes
1111.6 ms
14475.2 bytes
CountDownTimer 1090 ms
20960 bytes
1104 ms
13600 bytes
1098 ms
12960 bytes
1092 ms
12664 bytes
1094 ms
12792 bytes
1095.6 ms
14595.2 bytes

Execution times are above 1000 because the end of our speed test lies AFTER the timer executes. That is, after 1 second. Stats show that Thread has 111ms excess time in execution after a second, and across all runs, deviance between execution times is fluctuating.

On the other hand, CountDownTimer has only 95ms excess time in execution, and pretty much accurate across the runs (except the 1st and 2nd).

Although its different just by 120 on the average, it gave me quite a surprise that Thread used less memory.

Who wins this code clash? I say, CountDownTimer. It’s clean, it’s reliable. But unless you want your code to be pretty low level and highly customizable, go for Thread.

Comments and Suggestions are very welcome and appreciated.

Stats are generated by codes below

		final long startTime = System.currentTimeMillis();
		final Runtime rt = Runtime.getRuntime();
		rt.gc();
		final long memSys = rt.totalMemory() - rt.freeMemory();
		Thread k = new Thread(new Runnable() {
		    @Override
		    public void run() {
		        try {
		            for(itr=0 ; itr<1 ; itr++) {
		                Thread.sleep(1000);
		                runOnUiThread(new Runnable() {  
		                    @Override
		                    public void run() {
		                        tv.setText(itr+""); 
		                		Log.i("exec speed of Thread", System.currentTimeMillis()-startTime+"");
		        				long memory = ( rt.totalMemory() - rt.freeMemory() ) - memSys;
		        				Log.i("used memory in bytes", "Used Memory: "+memory);
		                        return;
		                    }
		                });
		            }
		            return;
		             
		        } catch (InterruptedException e) {
		            // TODO Auto-generated catch block
		            e.printStackTrace();
		        }
		    }
		});
		 
		k.start();
		final long startTime2 = System.currentTimeMillis();
		final Runtime rt = Runtime.getRuntime();
		rt.gc();
		final long memSys = rt.totalMemory() - rt.freeMemory();
		CountDownTimer timer = new CountDownTimer(1000, 1000) {
			 
		    public void onTick(long msNow) {
		        tv.setText("" + msNow / 1000);
		    }
		 
		    public void onFinish() {
		        tv.setText("00");
				Log.i("exec speed of CountDownTimer", System.currentTimeMillis()-startTime2+"");
				long memory = ( rt.totalMemory() - rt.freeMemory() ) - memSys;
				Log.i("used memory in bytes", "Used Memory: "+memory);
		    }
		 };
		  
		 timer.start();