The code that follows comes from p.58-61 of the book "Android Developer's Cookbook". The book introduces the code in the context of messages being a way to pass information between threads. It describes the code by saying: "The timer is run in a background thread so it does not block the UI thread, but it needs to update the UI whenever the time changes."
I'm confused because I don't see two threads. To me it seems that the main UI thread posts a runnable message to its own message queue (and that message then re-posts itself with a time-delay). Am I missing something?
package com.cookbook.background_timer;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class BackgroundTimer extends Activity {
//keep track of button presses, a main thread task
private int buttonPress=0;
TextView mButtonLabel;
//counter of time since app started, a background task
private long mStartTime = 0L;
private TextView mTimeLabel;
//Handler to handle the message to the timer task
private Handler mHandler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (mStartTime == 0L) {
mStartTime = SystemClock.uptimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 100);
}
mTimeLabel = (TextView) findViewById(R.id.text);
mButtonLabel = (TextView) findViewById(R.id.trigger);
Button startButton = (Button) findViewById(R.id.trigger);
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view){
mButtonLabel.setText("Pressed " + ++buttonPress + " times");
}
});
}
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
final long start = mStartTime;
long millis = SystemClock.uptimeMillis() - start;
int seconds = (int) (millis / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
mTimeLabel.setText("" + minutes + ":" + String.format("%02d",seconds));
mHandler.postDelayed(this, 200);
}
};
@Override
protected void onPause() {
mHandler.removeCallbacks(mUpdateTimeTask);
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
mHandler.postDelayed(mUpdateTimeTask, 100);
}
}
The second thread is kind of hidden. It's when you call postDelayed(mUpdateTImeTask,100) in onCreate(). The handler has a thread in it that counts down the delay time (100 milliseconds in this case) and then runs mUpdateTImeTask. Note that at the end of the run() method of mUpdateTimeTask, it puts itself back in the handler's timer thread by calling postDelayed() again.
The Android api has lots of classes like Handler and AsyncTask that make it easier to do multithreading. These classes hide a lot of the nuts and bolts of threading (which is what makes them nice to use). Unfortunately, that makes it hard to learn what's going on--you sort of have to know what's going on in order to learn it. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With