This note illustrates an important technique in Android, for calling a method (on the UI thread) after a short delay. You can use this to update the UI periodically, even when the user is not clicking anything.
To get started, you will need a Handler
object as an instance variable in your activity class:
Handler handler = new Handler();
If you need to import it manually:
import android.os.Handler
The Handler
method we’ll use here is called postDelayed
. It takes a Runnable
object (which is just anything with a run
method), and an integer number of milliseconds.
Here’s a simple “count-down” example you can incorporate into a hello-world activity with a TextView
:
final int INTERVAL = 1000; // milliseconds = 1 second
int timeRemaining = 20;
TextView textView;
Handler handler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.textView);
textView.setText(""+timeRemaining);
handler.postDelayed(new Runnable() {
@Override
public void run() {
timeRemaining--;
textView.setText(""+timeRemaining);
if(timeRemaining > 0) {
handler.postDelayed(this, INTERVAL);
}
}
}, INTERVAL);
}
When the activity opens, it shows the number 20, but then it counts down to zero, one number per second. Notice how postDelayed
is called from within onCreate
, but then again nested within the run
method – as long as the timeRemaining
is not yet zero.
I try to avoid the nested anonymous class syntax whenever possible – that’s where it says new Runnable() {…}
. A cleaner way is to make the activity itself runnable. That would look like this:
package com.example.countdown;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
public class CountdownActivity extends Activity implements Runnable {
final int INTERVAL = 1000; // milliseconds = 1 second
int timeRemaining = 20;
TextView textView;
Handler handler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.textView);
textView.setText(""+timeRemaining);
handler.postDelayed(this, INTERVAL);
}
@Override
public void run() {
timeRemaining--;
textView.setText("" + timeRemaining);
if (timeRemaining > 0) {
handler.postDelayed(this, INTERVAL);
}
}
}
Using this technique, I managed to make the rabbit-pellet game so that I don’t have to hit the arrow buttons hundreds of times. Instead, I just hold it down and the rabbit keeps moving. In this program, the delay interval is 50 milliseconds (20 times per second).