TimePicker

The TimePicker updates the one-line TextView. The “Now” Button updates the TimePicker. This example has a TimePicker without a TimePickerDialog. The TimePicker tutorial has a TimePicker with a TimePickerDialog. Here is my example of a TimePickerDialog.

The TextView has to be final in order to be mentioned in onTimeChanged. The TimePicker had to be final in order to be mentioned in onClick. The hour passed to onTimeChanged is a 24-hour hour. onTimeChanged will not be called if the TimePicker is changed to the same time that it currently holds.

The time displayed the TextView is formatted in 12- or 24-hour format, depending on the setting set by the Android Settings app. Warning: the getTimeFormat method of class android.text.format.DateFormat returns an object of class java.text.DateFormat. The two DateFormats are two different classes.

Source code in TimePicker.zip

  1. TimePickerActivity.java
  2. R.java
  3. main.xml
  4. AndroidManifest.xml

Another example of a TimePicker: ApiDemos/View/Date Widgets/2. Inline

  1. DateWidgets2.java
  2. date_widgets_example_2.xml

Things to try

  1. Would it be clearer to change
    				textView.setText(DateFormat.getTimeFormat(TimePickerActivity.this).format(calendar.getTime()));
    
    to
    				java.text.DateFormat dateFormat = DateFormat.getTimeFormat(TimePickerActivity.this));
    				textView.setText(dateFormat.format(calendar.getTime()));
    
    ?

  2. Since the Button and TextView have android:layout_width="wrap_content" rather than the usual android:layout_width="fill_parent" in main.xml, we were able to center them horizontally with android:layout_gravity="center_horizontal". What happens when you remove the android:layout_gravity="center_horizontal"?

  3. Does the TimePicker automatically go into 24-hour mode when you chnage the settings in the Settings app, or do you have to call is24HourFormat and setIs24HourView manually?

  4. Create a Thread that will update the TextView once per second. A Thread object has a method named run. Create the following non-nested class in the file TimePickerActivity.java. The run method sends a Message, once per second, to the Handler that is plugged into the Thread. When the Handler receives the Message, the Handler updates the TextView.

    Why do we need a separate Handler object? Well, the Android UI is single-threaded. That means a TextView can be written only by the Thread that created the TextView. But the TextView and the Handler were both created by the onCreate method of the Activity, so they both belong to the same thread. See main use #2 of a Handler.

    final class MyThread extends Thread {
    	final Handler handler;
    	final Calendar calendar = Calendar.getInstance();
    
    	MyThread(Handler handler) {
    		this.handler = handler;
    	}
    
    	@Override
    	public void run() {
    		for (;;) {
    			try {
    				//1000 milliseconds == 1 second
    				Thread.sleep(1000);
    			} catch (InterruptedException interruptedException) {
    				Log.e("ERROR", "sleep interrupted", interruptedException);
    			}
    
    			final Message message = handler.obtainMessage(); //Get an empty Message.
    			calendar.setTime(new Date());
    			message.arg1 = calendar.get(Calendar.MINUTE);	//Fill it up.
    			message.arg2 = calendar.get(Calendar.SECOND);
    
    			//Send the mesage to the Handler.
    			//Calls handleMessage, below.
    			handler.sendMessage(message);
    		}
    	}
    }
    

    At the end of onCreate, create the Handler and the Thread. Plug the Handler into the Thread and start the Thread.

    %02d formats the integer with at least two digits, even if it is a single-digit number. Add a leading zero if necessary.

    		final Handler handler = new Handler() {
    			@Override
    			public void handleMessage(Message message) {
    				textView.setText(String.format("%d:%02d", message.arg1, message.arg2));
    			}
    		};
    
    		final MyThread myThread = new MyThread(handler);
    		myThread.start();
    

  5. arg1 occupies 32 bits. Encode the hour in the 16 high-order bits, the minute in the 16 low-order bits.
    		//in the run method of MyThread
    
    		message.arg1 = calendar.get(Calendar.HOUR_OF_DAY) << 16 | calendar.get(Calendar.MINUTE)
    
    		//in the handleMessage method of the Handler
    
    		textView.setText(String.format("%d%02d:%02d",
    			message.arg1 >>> 16,	//prevent sign extension
    			message.arg1 & 0xFF,	//mask off the 16 high-order bits
    			message.arg2
    		));
    

  6. Use the obj field of the Message instead of arg1 and arg2. Create the following non-nested class in the file TimePickerActivity.java. No reference to Master and Commander is intended.
    final class Hms {
    	public int hour;
    	public int minute;
    	public int second;
    
    	Hms(int hour, int minute, int second) {
    		this.hour = hour;
    		this.minute = minute;
    		this.second = second;
    	}
    }
    
    		//in the run method of MyThread
    
    		message.obj = new Hms(
    			calendar.get(Calendar.HOUR_OF_DAY),
    			calendar.get(Calendar.MINUTE),
    			calendar.get(Calendar.SECOND)
    		);
    
    		//in the handleMessage method of the Handler
    
    		textView.setText(String.format("%d:%02d:%02d",
    			((Hms)message.obj).hour,
    			((Hms)message.obj).minute,
    			((Hms)message.obj).second
    		));
    

  7. Can we use the post method of class View to let the second thread communicate with the main thread?