Getting Choosy with Dates and Times

A Task Reminder application without a way to set the date and time is a poor Task Reminder application — it would only be a simple task list application.

If you’ve programmed dates and times in another programming language, you realize that building a mechanism for a user to enter the date and time can be a painstaking process. The Android platform comes to your rescue by providing two classes to assist you: DatePicker and TimePicker. These pickers also provide built-in classes for opening a dialog box where the user selects a date and time. Therefore, you can either embed the DatePicker or TimePicker into your application’s views or use the DialogFragment classes.

Creating picker buttons

The reminder_edit.xml file contains mechanisms to help show the DatePicker and TimePicker (under the EditText definitions described earlier). These two buttons have labels above them, as shown in Listing 11-1.

Listing 11-1: The Date and Time Buttons with Their Corresponding TextView Labels

<TextView android:layout_width=”wrap_content” →1

android:layout_height=”wrap_content”

android:text=”@string/date” />

<Button →4

android:id=”@+id/reminder_date”

android:layout_height=”wrap_content”

android:layout_width=”wrap_content”

/>

<TextView android:layout_width=”wrap_content” →9

android:layout_height=”wrap_content”

android:text=”@string/time” />

<Button →12

android:id=”@+id/reminder_time”

android:layout_height=”wrap_content”

android:layout_width=”wrap_content”

/>

The code lines are explained in this list:

1 The TextView label for the Date button; displays the value of “Reminder Date” according to the string resource

4 Defines a button that the user clicks to open the DatePicker DialogFragment (as explained in the following section)

9 The TextView label for the Time button; displays the value of “Reminder Time” according to the string resource

12 Defines a button that the user clicks to open the TimePickerDialogFragment (explained in the section, “Creating the time picker”)

Creating the date picker

A user who clicks the Date button should be able to edit the date, as described in the following several sections.

Setting up the Date button click listener

To set up the Date button click listener, open the activity where your code will be placed. For the Task Reminder application, open the ReminderEditFragment.java file.

Add the code lines shown in bold in Listing 11-2 to the onCreateView() method.

Listing 11-2: Implementing the Date Button Click Listener

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

View v = inflater.inflate(R.layout.reminder_edit, container, false);

mTitleText = (EditText) v.findViewById(R.id.title);

mBodyText = (EditText) v.findViewById(R.id.body);

mDateButton = (Button) v.findViewById(R.id.reminder_date);

mTimeButton = (Button) v.findViewById(R.id.reminder_time);

mConfirmButton = (Button) v.findViewById(R.id.confirm);

mDateButton.setOnClickListener(new View.OnClickListener() { 13

@Override

public void onClick(View v) { 15

showDatePicker(); 16

}

});

return v;

}

The numbered lines are described in this list:

13 Sets the onClickListener() for the mDateButton. The onClickListener() executes when the button is clicked. The action that takes place on the button click is shown on line 16.

15 Overrides the default click behavior of the button so that you can provide your own set of actions to perform. The View v parameter is the view that was clicked.

16 Defines what you want to happen when the button is clicked; calls a method on the showDatePicker() fragment, as explained in the later section “Creating the showDatePicker() method.”

Creating the DatePickerDialogFragment

The Android operating system comes supplied with a built-in Date PickerDialog that lets users select (rather than type) a date. It doesn’t come wrapped neatly in a fragment, so you have to do it yourself.

technicalstuff.eps The old dialog objects were designed to be called from activities, not from fragments. When opening a dialog box from a fragment, you have to use a subclass of the DialogFragment class if you want the dialog box to behave properly.

Create a new file, name it DatePickerDialogFragment, and add the following code:

package com.dummies.android.taskreminder;

import android.app.DatePickerDialog;

import android.app.Dialog;

import android.os.Bundle;

import android.support.v4.app.DialogFragment; →6

public class DatePickerDialogFragment extends DialogFragment {

@Override

public Dialog onCreateDialog(Bundle savedInstanceState) { →10

Bundle args = getArguments(); →11

Fragment editFragment = getFragmentManager() →12

.findFragmentByTag(

ReminderEditFragment.DEFAULT_EDIT_FRAGMENT_TAG);

OnDateSetListener listener = (OnDateSetListener) editFragment; →15

return new DatePickerDialog(getActivity(), listener, →17

args.getInt(ReminderEditFragment.YEAR),

args.getInt(ReminderEditFragment.MONTH),

args.getInt(ReminderEditFragment.DAY));

}

}

Here’s how the code works:

6 Be sure to use the android.support.v4.app.* imports and not their equivalents from android.app.

10 The method that’s called when Android wishes to display the DatePicker dialog box. This method creates it and returns it.

remember.eps Sometimes you may need to use savedInstanceState to restore the state from previous instances. However, in this case, the dialog box already does it for you, so you can safely ignore savedInstanceState in this method.

11 Constructor-like arguments for a fragment are passed via set Arguments(), not via the fragment’s constructor, so this line retrieves those arguments using getArguments(), which you need on line 17.

12 Asks the FragmentManager to find the fragment named DEFAULT_EDIT_FRAGMENT_TAG, which is the ReminderEditFragment.

15 Casts the editFragment to an OnDateSetListener. The dialog box created by the onCreateDialog needs the OnDateSetListener object to inform the ReminderEditFragment when the user has picked a date.

17 This line calls the DatePickerDialog constructor and passes getActivity(), the current context listener obtained on line 12, and args.getInt(ReminderEditFragment.YEAR), args.getInt(ReminderEditFragment.MONTH), args.getInt(ReminderEditFragment.DAY), the year, month, and day, as specified in the arguments to this fragment.

Creating the showDatePicker() method

After you have a DatePickerDialogFragment class, you can create an instance of it and show it to the user. The date button’s onClickListener called showDatePicker, so you can implement showDatePicker() now. Add the following code to the ReminderEditFragment class after your onCreateView():

//

// Dialog Constants

//

static final String YEAR = “year”;

static final String MONTH = “month”;

static final String DAY = “day”;

static final String HOUR = “hour”;

static final String MINS = “mins”;

static final String CALENDAR = “calendar”;

private void showDatePicker() {

FragmentTransaction ft = getFragmentManager().beginTransaction(); →11

DialogFragment newFragment = new DatePickerDialogFragment(); →12

Bundle args = new Bundle(); →13

args.putInt(YEAR, mCalendar.get(Calendar.YEAR)); →14

args.putInt(MONTH, mCalendar.get(Calendar.MONTH));

args.putInt(DAY, mCalendar.get(Calendar.DAY_OF_MONTH));

newFragment.setArguments(args); →17

newFragment.show(ft, “datePicker”); →18

}

This is how the code works:

11 Implements a fragment transaction for the new fragment.

12 Creates a DatePickerDialogFragment instance.

13 Creates the fragment constructor arguments in a bundle.

14 Sets the year, month, and day of the dialog box fragment to the year, month, and day set in the mCalendar object.

17 Sets the fragment’s arguments to the values in the bundle created in line 4.

18 Shows the DatePicker dialog box fragment, which allows the dialog box to open onscreen. Because show() calls commit(), you don’t need to call it explicitly.

Creating the time picker

The TimePickerDialogFragment allows users to select a time to be reminded of a pending task.

Setting up the Time button click listener

Setting up a TimePickerDialogFragment is almost identical to setting up a DatePickerDialogFragment. You first declare the onClickListener() for the Time button. In ReminderEditFragment.onCreateView(), add the following code snippet right before the return at the end:

mTimeButton.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

showTimePicker();

}

});

This method is the same as the Date button’s onClickListener(), except that you’re calling showTimePicker() instead of showDatePicker().

Creating the showTimePicker() method

To help you create the showTimePicker() method, the full method definition, with code, is shown in Listing 11-3.

Listing 11-3: The showTimePicker() Method

private void showTimePicker() {

FragmentTransaction ft = getFragmentManager().beginTransaction();

DialogFragment newFragment = new TimePickerDialogFragment(); →3

Bundle args = new Bundle();

args.putInt(HOUR, mCalendar.get(Calendar.HOUR_OF_DAY)); →5

args.putInt(MINS, mCalendar.get(Calendar.MINUTE));

newFragment.setArguments(args);

newFragment.show(ft, “timePicker”); →8

}

The code in Listing 11-3 is fairly straightforward because it’s almost identical to that of the showDatePicker() method. However, you can see differences on these lines:

3 Creates a new instance of TimePickerDialogFragment.

5 Sets the arguments for the TimePickerDialogFragment to be the calendar’s hour and minute components.

8 Shows the fragment using the tag “timePicker”, which isn’t visible to the user.

Creating the TimePickerDialogFragment

The Android operating system comes supplied with a built-in TimePicker Dialog that lets users select (rather than type) a time. Like the Date PickerDialog, the TimePickerDialog doesn’t come wrapped neatly in a fragment, so you have to do it yourself.

The code for the TimePickerDialogFragment is nearly identical to the DatePickerDialogFragment except that it wraps a TimePickerDialog instead of a DatePickerDialog:

package com.dummies.android.taskreminder;

import android.app.Dialog;

import android.app.TimePickerDialog;

import android.app.TimePickerDialog.OnTimeSetListener;

import android.os.Bundle;

import android.support.v4.app.DialogFragment;

public class TimePickerDialogFragment extends DialogFragment {

@Override

public Dialog onCreateDialog(Bundle savedInstanceState) {

Bundle args = getArguments();

OnTimeSetListener listener = (OnTimeSetListener) getFragmentManager()

.findFragmentByTag(

ReminderEditFragment.DEFAULT_EDIT_FRAGMENT_TAG);

return new TimePickerDialog(getActivity(), listener,

args.getInt(ReminderEditFragment.HOUR),

args.getInt(ReminderEditFragment.MINS), false);

}

}

Adding the fragment to handle date picker and time picker callbacks

The remaining step in getting your date and time pickers working is to implement the OnDateSetListener and OnTimeSetListener so that the dialog box stores the new date and time when the user chooses a date or time. You store that value in a Calendar object. It requires three steps:

1. Add the OnDateSetListener and OnTimeSetListener interfaces to the ReminderEditFragment.

2. Add a Calendar object called mCalender to store the values that the user sets.

3. Set the mCalendar object when the user picks a date or time, and then update the date and time buttons on the user interface with the new values.

From Listing 11-4, add the code in bold to the ReminderEditFragment class to get your date and time pickers working.

Listing 11-4: Adding the OnDateSetListener and OnTimeSetListener interfaces to the ReminderEditFragment class

public class ReminderEditFragment extends Fragment implements

OnDateSetListener, OnTimeSetListener { →2

private static final String DATE_FORMAT = “yyyy-MM-dd”;

private static final String TIME_FORMAT = “kk:mm”;

private Calendar mCalendar; 7

@Override

public void onDateSet(DatePicker view, int year, int monthOfYear,

int dayOfMonth) { 11

mCalendar.set(Calendar.YEAR, year);

mCalendar.set(Calendar.MONTH, monthOfYear);

mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);

updateButtons(); 15

}

@Override

public void onTimeSet(TimePicker view, int hour, int minute) { 19

mCalendar.set(Calendar.HOUR_OF_DAY, hour);

mCalendar.set(Calendar.MINUTE, minute);

updateButtons();

}

private void updateButtons() { 25

// Set the time button text

SimpleDateFormat timeFormat = new SimpleDateFormat(TIME_FORMAT);

String timeForButton = timeFormat.format(mCalendar.getTime());

mTimeButton.setText(timeForButton);

// Set the date button text

SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);

String dateForButton = dateFormat.format(mCalendar.getTime());

mDateButton.setText(dateForButton);

}

}

Listing 11-4 works this way:

2 Implements the OnDateSetListener and OnTimeSetListener callback objects.

7 Stores the user’s date and time selections with a standard Java Calendar object.

11 Implements the onDateSet() method of the OnDateSet Listener. When the user sets the date in the dialog box, the Calendar object is updated to reflect the new date.

15 Updates the user interface buttons to reflect the new date and time.

19 Sets the hour and minutes of the Calendar object for the onTimeSet() method of the OnTimeSetListener.

25 Updates the buttons to reflect the values selected by the user. The Calendar object is converted into a couple of text strings — one for the date button and one for the time button — which are then used to set the text on those buttons. The first Simple DateFormat uses TIME_FORMAT to produce a time string in the format kk:mm; the second SimpleDateFormat uses DATE_FORMAT to produce a date string in the format yyyy-MM-dd.

tip.eps Visit http://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html for more details about SimpleDateFormat date and time formatting.

To add the mCalendar object, add the following lines to onCreate():

if (savedInstanceState != null

&& savedInstanceState.containsKey(CALENDAR)) { →2

mCalendar = (Calendar) savedInstanceState.getSerializable(CALENDAR); →3

} else {

mCalendar = Calendar.getInstance(); →5

}

The code works this way:

2 This line checks a savedInstanceState for a CALENDAR field indicating that an earlier activity was saved and temporarily destroyed, such as rotating from Landscape mode to Portrait mode.

If you’re creating a brand-new instance of this fragment, saved InstanceState is null and the application moves to line 5.

3 If the savedInstanceState includes a CALENDAR field, this line pulls out the associated Calendar object and sets mCalendar to that value.

5 When you’re creating a ReminderEditFragment from scratch and you aren’t resurrecting a previous instance, this line sets mCalendar to a new Calendar instance (obtained by calling Calendar.getInstance()). New Calendar instances always default to the current date and time.

Now the mCalendar instance is initialized.

Because onCreate() is looking for a calendar instance in savedInstance State on lines 1-2, you have to save your mCalendar object to the saved InstanceState whenever your activity is destroyed. That way, onCreate() can pick up the saved value if the activity is ever re-created. To do so, add the following method to your class:

@Override

public void onSaveInstanceState(Bundle outState) { →2

super.onSaveInstanceState(outState);

// Save the calendar instance in case the user changed it →4

outState.putSerializable(CALENDAR, mCalendar);

}

The code works this way:

2 onSaveInstanceState() is a special method that Android calls whenever it’s about to destroy a fragment. You can store any data that you might be using, so if Android ever needs to re-create the same activity, it has all the necessary information.

Most views already know how to store their state and resurrect themselves, and they do it in the call to super.onSaveInstance State().

4 The only task you have to handle manually is the mCalendar field, so this line stores it in the bundle to use later when the activity is re-created.

Calendar objects can be serialized (stored as data), so this line uses the putSerializable() method to save them.

tip.eps Find out more information about Java serialization at http://java.sun.com/developer/technicalArticles/Programming/serialization .

You can save all kinds of other types into bundles, such as ints, longs, strings, parcelables, and other exotic elements, so check http://d.android.com/reference/android/os/Bundle.html to see the full list.

technicalstuff.eps
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset