Download Mobile Application Frameworks and Services

Document related concepts
no text concepts found
Transcript
Mobile Application
Frameworks and Services
Lecture: Graphical User Interface II
Dr. Panayiotis Alefragis
Professor of Applications
Masters Science Program:
Technologies and Infrastructures for Broadband Applications and Services
1
Buttons and
Similar Clickable Widgets
Originals of Slides and Source Code for Examples:
http://www.coreservlets.com/android-tutorial/
Topics in This Section
• Buttons
• ImageButtons each with single image
• ImageButtons each with 3 (normal/focused/pressed)
images
• RadioButtons with OnClickListener on each
• RadioButtons
with
OnCheckedChangeListener
on
RadioGroup
• CheckBoxes
• ToggleButtons
3
General Approach
for Widget Examples
Widget Lectures Combined in Single Project
• Main screen
– Lets user choose screens on various Widget topics
• Other screens
– Correspond to separate lectures.
• One screen for lecture on Buttons, another for lecture on Spinners,
another for number input, etc.
• Separate layout files
– main.xml, buttons.xml, spinners.xml, etc. See next slide.
• Separate Java classes
– WidgetActivity.java, ButtonActivity.java, SpinnerActivity.java, etc.
• Shared strings file
– strings.xml has separate sections for each lecture, but same file
5
Layout Files for Widget Lectures
• Separate layout files for each Activity
– res/layout/main.xml
• Gives
layout
for
main
setContentView(R.layout.main);
screen.
Loaded
with
– res/layout/buttons.xml
• Gives layout for screen on Button and related Widgets. Loaded with
setContentView(R.layout.buttons);
– res/layout/spinners.xml
• Gives layout for screen on Spinners (i.e., combo boxes). Loaded with
setContentView(R.layout.spinners);
• Two common layout attributes
– android:layout_width, android:layout_height
• match_parent (fill up space in enclosing View)
• wrap_content (use natural size)
6
Switching Activities: Summary
• Switches Activities with Intents
– Main screen has buttons to navigate to other Activities
– Return to original screen with phone’s “back” button
• Syntax required to start new Activity
– Java
• Intent newActivity = new Intent(this, NewActivity.class);
• startActivity(newActivity);
– XML
• Requires entry in AndroidManifest.xml (which is part of downloadable
Eclipse project for Widgets)
– More details
• Code and some information given in Spinner lecture
• Even more information given in later lecture on Intents
7
Overall Widget Project Layout
Java code
Images and XML files that refer to sets of images.
The layout files will refer to these images via
@drawable/base_file_name (e.g., @drawable/gps).
The first ImageButton example will use an image file,
and the second ImageButton example will use an
XML file containing references to image files.
Layout files. The Java code will refer to the overall layouts via
R.layout.base_file_name (R.layout.main, R.layout.buttons, etc.).
The Java code will refer to specific GUI elements with
findViewById(R.id.element_id).
Strings. The Java code will refer to these via
getString(R.string.string_name). The layout files will refer to these
with @string/string_name. You can also define arrays of strings
here, or put the arrays in a separate file typically called arrays.xml.
Arrays are used in the next lecture on Spinners.
8
In order for one Activity to start another Activity in the same project, you need
some entries in here. See Spinner lecture.
Approach for
Button-Related Examples
Summary of Layout
Horizontal LinearLayout (with 3 Buttons)
Horizontal LinearLayout (with 3 ImageButtons)
Horizontal LinearLayout (with 3 ImageButtons)
Horizontal RadioGroup
(with 3 RadioButtons)
Vertical
LinearLayout
Horizontal RadioGroup
(with 3 RadioButtons)
Horizontal LinearLayout (with 3 CheckBoxes)
Horizontal LinearLayout (with 3 ToggleButtons)
10
An upcoming tutorial section gives details on using layouts. However, you can do a
pretty lot now by knowing just two simple things:
1)
You can make some pretty complex layouts by nesting horizontal and vertical
layouts inside each other.
2)
You can experiment interactively with the visual layout editor in Eclipse. Edit
layout file and click on Graphical Layout.
XML: Layout File
(res/layout/buttons.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-One entry for each row in previous slide.
These entries are shown in upcoming slides.
-->
</LinearLayout>
11
XML: Strings File
(res/values/strings.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Initial screen -->
<string name="app_name">...</string>
<string name="show_buttons_button_label">...</string>
<string name="show_spinners_button_label">...</string>
<!-- Buttons example -->
<!-- Shown in this lecture -->
<!-- Spinners example -->
<!-- Shown in next lecture -->
</resources>
12
Java (ButtonActivity.java)
public class ButtonActivity extends Activity {
...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.buttons);
...
}
private void showToast(String text) {
Toast.makeText(this,
Toast.LENGTH_LONG).show();
}
...
}
13
text,
Button
Button
• Idea
– A push button displaying text
• Main Listener type
– View.OnClickListener
• If you specify the handler method in the XML file, you never explicitly
refer to this Listener class.
• Key XML attributes
– android:text
• The label of the button. Can also be manipulated in Java with setText
and getText
– android:onClick
• The event handler method. As shown in event-handling lecture, you
can also use android:id and then have Java code programmatically
assign event handler.
15
XML: Layout File Entry
(Part of res/layout/buttons.xml)
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<Button
android:text="@string/hi_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showButtonText"/>
<Button
android:text="@string/bye_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showButtonText"/>
<Button
android:text="@string/yo_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showButtonText"/>
</LinearLayout>
16
XML: Strings File Entries
(Part of res/values/strings.xml)
<string name="hi_label">Hi!</string>
<string name="bye_label">Bye!</string>
<string name="yo_label">Yo!</string>
<string name="button_message_template">
You clicked the \'%s\' Widget.
</string>
These are the labels referred
to in previous slide
The event handler method
will use String.format and this
template to produce a
message that will be shown
in a Toast (short-lived popup
message) when a Button is
clicked.
17
Java (Relevant Parts)
public class ButtonActivity extends Activity {
private String mButtonMessageTemplate;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.buttons);
mButtonMessageTemplate =
getString(R.string.button_message_template);
}
public void showButtonText(View clickedButton) {
Button button = (Button)clickedButton;
CharSequence text = button.getText();
String message =
This is the method specified
String.format(mButtonMessageTemplate, text);
for each Button via the
showToast(message);
android:onClick attribute in the
layout file.
}
}
18
Results
19
Emulator
Phone
ImageButton
(Each with Single Image)
ImageButton, Variation 1
• Idea
– A push button displaying an image
• Main Listener type
– View.OnClickListener
If you just want to display an
image, but not take action
when it is clicked, see the
ImageView class.
• Key XML attributes
– android:src
• The image for the button. Refers to the base name (minus the
extension) of an image file in the res/drawable folder
– Supported
formats
are
png,
jpeg,
gif,
and
You can also refer to a drawable XML file as in next example.
– The localization lecture will talk about drawable-xdpi folders
• Can also be set in Java with setImageDrawable
– android:onClick
• The event handler method
21
bmp.
XML: Layout File Entry
(Part of res/layout/buttons.xml)
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<ImageButton
android:src="@drawable/android_platform"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showImageButton1Info"/>
<ImageButton
android:src="@drawable/camera_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showImageButton2Info"/>
<ImageButton
android:src="@drawable/gps"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showImageButton3Info"/>
</LinearLayout>
22
Refers to
res/drawable/android_platform.png
Refers to
res/drawable/camera_phone.png
Refers to res/drawable/gps.png
XML: Strings File Entries
(Part of res/values/strings.xml)
<string name="image_button_message_template">
You clicked the ImageButton that displays %s.
</string>
<string name="image_button_1_image">
The event handler method
the android_platform.png image
will use String.format, this
</string>
template, and the
descriptions below to
<string name="image_button_2_image">
produce a message that will
be shown in a Toast when an
the camera_phone.png image
ImageButton is clicked.
</string>
<string name="image_button_3_image">
the gps.png image
</string>
23
Java (Relevant Parts)
public class ButtonActivity extends Activity {
private String mImageButtonMessageTemplate;
@Override
public void onCreate(Bundle savedInstanceState) {
...
mImageButtonMessageTemplate =
getString(R.string.image_button_message_template);
}
public void showImageButton1Info(View clickedImageButton) {
showImageButtonInfo(R.string.image_button_1_image);
}
...
private void showImageButtonInfo(int imageId) {
String image = getString(imageId);
String message =
This is the method specified for the first
ImageButton via the android:onClick attribute
String.format(mImageButtonMessageTemplate,
image);
in the layout file. Methods for the other
showToast(message);
ImageButtons are similar.
}
}
24
Results (Emulator)
25
ImageButton
(Each with 3 Images)
ImageButton, Variation 2
• Idea
– A push button displaying one of three images, depending upon the
situation
• Main Listener type
– View.OnClickListener
• Key XML attributes
– android:src
• The image descriptor file for the button. Refers to the base name
(minus the .xml extension) of an XML file in the res/drawable folder
– The file, in turn, refers to three regular images in drawable folder
• Can also be set in Java with setImageDrawable
– android:onClick
• The event handler method
27
Individual Image Files
vs. XML Files
•
Individual image files
– Android will use the same image
for all states of the button
(normal, focused, pressed)
– Android will change the
background color when focused
or pressed. This affects the
transparent
pixels.
•
XML files
– Android will use a different
image for each state of the
button
(normal,
focused,
pressed)
– The different images can have
different foreground colors, not
just different backgrounds.
28
To get images for practicing, look in android-sdkinstall-dir/platform-x/data/res/drawable-xdpi.
Or, do a Google search for free icons. Also, see
http://developer.android.com/guide/developing/tools/
draw9patch.html for building your own images.
Image Descriptor File
(res/drawable/button_android.xml)
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/android_pressed" />
<item android:state_focused="true"
android:drawable="@drawable/android_focused" />
<item android:drawable="@drawable/android_normal" />
</selector>
These are the actual image
files for each of the three
possible states of the
ImageButton.
The order of the three files matters. For more detail, see
http://developer.android.com/reference/android/widget/ImageButton.html
29
XML: Layout File Entry
(Part of res/layout/buttons.xml)
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<ImageButton
android:src="@drawable/button_android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showImageButton4Info"/>
<ImageButton
android:src="@drawable/button_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showImageButton5Info"/>
<ImageButton
android:src="@drawable/button_rating_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showImageButton6Info"/>
</LinearLayout>
30
Refers to res/drawable/button_android.xml.
This, in turn, refers to three regular image
files. Code on previous slide.
Refers to res/drawable/button_dialog.xml.
This, in turn, refers to three regular image
files.
Refers to
res/drawable/button_rating_star.xml. This,
in turn, refers to three regular image files.
XML: Strings File Entries
(Part of res/values/strings.xml)
<string name="image_button_message_template">
You clicked the ImageButton that displays %s.
</string>
The event handler method will use
String.format, this template, and the
descriptions below to produce a
message that will be shown in a
Toast when an ImageButton is
clicked. This is just a copy of entry
already shown in previous
ImageButton example.
<string name="image_button_4_image">
the Drawable defined in button_android.xml
</string>
<string name="image_button_5_image">
the Drawable defined in button_dialog.xml
</string>
<string name="image_button_6_image">
the
Drawable
defined
in
button_rating_star.xml
</string>
31
Java (Relevant Parts)
public class ButtonActivity extends Activity {
private String mImageButtonMessageTemplate;
@Override
public void onCreate(Bundle savedInstanceState) {
...
mImageButtonMessageTemplate =
getString(R.string.image_button_message_template);
}
public void showImageButton4Info(View clickedImageButton) {
showImageButtonInfo(R.string.image_button_4_image);
}
...
private void showImageButtonInfo(int imageId) {
String image = getString(imageId);
String message =
This is the method specified for the first
these 3 ImageButtons via the
String.format(mImageButtonMessageTemplate,ofandroid:onClick
image);
attribute in the layout
showToast(message);
file. Methods for the other ImageButtons
are similar.
}
}
32
Results (Emulator)
33
RadioButton
(with Event Handler Attached to Each)
RadioButton
• Idea
– A button for choosing a single option among alternatives
• Main Listener types
– View.OnClickListener
• Assign to each RadioButton if you only care about which has been
pressed most recently. But also see upcoming example for Listener
attached to the RadioGroup.
– No need to explicitly refer to Listener when using android:onClick
– No Listener at all
• Some apps take no action when RadioButton is clicked, but instead
query the RadioGroup later to find selection
• Key XML attributes
– android:text, android:onClick
• Same as in previous examples.
35
RadioGroup
• Idea
– Similar to LinearLayout, but specifically for organizing
RadioButtons.
– Makes the RadioButtons exclusive (checking one causes previous
selection to become unchecked)
• Main Listener types
– RadioGroup.OnCheckedChangeListener
• Assign to RadioGroup if you want to keep track of both current and
previous selections
• You can also call getCheckedRadioButtonId, if you don’t need to
respond immediately, but want to find selection later
• Key XML attributes
– Mostly same as for LinearLayout
– Use android:id if you want to programmatically set an
OnCheckedChangeListener
• No android:onBlah to set RadioGroup Listener in XML
36
First Example: Event Handlers Attached to
Each RadioButton
• Idea
– Respond to clicks on each RadioButton by showing Toast saying
which one was pressed.
• Approach
– Put RadioButtons inside RadioGroup so that they are mutually
exclusive.
– To assign event handlers, use android:onClick for each RadioButton
– No id for RadioGroup. No Listener for RadioGroup
37
XML: Layout File Entry
(Part of res/layout/buttons.xml)
<RadioGroup
android:gravity="center_horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal">
<RadioButton
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/hi_label"
android:onClick="showButtonText"/>
<RadioButton
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/bye_label"
android:onClick="showButtonText"/>
<RadioButton
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/yo_label"
android:onClick="showButtonText"/>
</RadioGroup>
38
This first example uses click
handlers attached to each
RadioButton.
Strings File and Java Code
• Nothing new for this example
– Strings file
• Already showed button labels and button_message_template
– Java code
• Already showed makeToast and showButtonText
39
Results (Emulator)
40
RadioButton
(with Event Handler
Attached to RadioGroup)
Second Example: Event Handler Attached to
RadioGroup
• Idea
– Respond to clicks by showing Toast saying which one was pressed
and which one was previously selected.
• Approach
– Put RadioButtons inside RadioGroup so that they are mutually
exclusive.
• Same as last example
– In XML, give id to RadioGroup.
– In Java, find RadioGroup and call setOnCheckedChangeListener
42
XML: Layout File Entry
(Part of res/layout/buttons.xml)
<RadioGroup
android:id="@+id/radio_group"
android:gravity="center_horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal">
<RadioButton
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/hi_label"/>
<RadioButton
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/bye_label"/>
<RadioButton
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/yo_label"/>
</RadioGroup>
43
The id is needed so that Java can get a
reference and programmatically set the
OnCheckedChangeListener.
RadioButtons do not have
android:onClick entries
XML: Strings File Entries
(Part of res/values/strings.xml)
<string name="new_selection_message_template">
You selected the \'%s\' RadioButton.
There was no previous selection.
</string>
<string
name="changed_selection_message_template"
formatted="false">
You selected the \'%s\' RadioButton.
Previous selection was \'%s\'.
</string>
The event handler method will use String.format, one of these templates,
the current selection, and the previous selection to produce a message
that will be shown in a Toast when a RadioButton is clicked.
Use formatted="false" if a string has more than one %s placeholder.
44
Java (Relevant Parts)
public class ButtonActivity extends Activity {
...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.buttons);
...
RadioGroup radioGroup =
(RadioGroup)findViewById(R.id.radio_group);
radioGroup.setOnCheckedChangeListener(new
RadioGroupInfo());
}
Continued on next page.
RadioGroupInfo is an inner class inside
ButtonActivity.
45
Java
(Relevant Parts, Continued)
private class RadioGroupInfo implements OnCheckedChangeListener {
private RadioButton mLastChecked;
private String mNewSelectionMessageTemplate;
private String mChangedSelectionMessageTemplate;
public RadioGroupInfo() {
mNewSelectionMessageTemplate =
getString(R.string.new_selection_message_template);
mChangedSelectionMessageTemplate =
getString(R.string.changed_selection_message_template);
}
Top of the inner class
46
Java
(Relevant Parts, Continued)
@Override
public void onCheckedChanged(RadioGroup group, int checkedId)
{
RadioButton newChecked =
(RadioButton)findViewById(checkedId);
String message;
if (mLastChecked == null) { // No previous selection
message = String.format(mNewSelectionMessageTemplate,
newChecked.getText());
} else {
message
=
String.format(mChangedSelectionMessageTemplate,
newChecked.getText(),
mLastChecked.getText());
}
mLastChecked = newChecked;
showToast(message);
}
}
}
Bottom of the inner class. Keeps track of
current and previous selections.
47
Results (Emulator)
48
CheckBox
CheckBox
• Idea
– A button with two states (checked and unchecked)
• Has visual indicator to show whether it is checked
• In Java, use isChecked() to determine state. Use setChecked to
programmatically change the state.
– Same text in both states (unlike ToggleButton)
• Main Listener types
– View.OnClickListener
– No Listener at all
• Take no action when CheckBox is clicked, but instead query the
CheckBox later to find if it is checked or not
• Key XML attributes
– android:text, android:onClick
• Same as in previous examples
50
XML: Layout File Entry
(Part of res/layout/buttons.xml)
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<CheckBox
android:text="@string/hi_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showButtonText"/>
<CheckBox
android:text="@string/bye_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showButtonText"/>
<CheckBox
android:text="@string/yo_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showButtonText"/>
</LinearLayout>
51
Note that the class name is
CheckBox, not Checkbox
(as in AWT).
Strings File and Java Code
• Nothing new for this example
– Strings file
• Already showed button labels and button_message_template
– Java code
• Already showed makeToast and showButtonText
52
Results (Emulator)
53
ToggleButton
ToggleButton
• Idea
– A button with two states (checked and unchecked)
• Has visual indicator to show whether it is checked
• In Java, use isChecked() to determine state. Use setChecked to programmatically
change the state.
– Has different text for each state (unlike CheckBox)
• Main Listener types
– View.OnClickListener
– No Listener at all
• Take no action when ToggleButton is clicked, but instead query the ToggleButton
later to find if it is checked or not
• Key XML attributes
– android:textOn, android:textOff
• The text for the two states. If you omit this, then the text is automatically ON and OFF
(in caps)
– android:onClick
• Same as in previous examples
55
XML: Layout File Entry
(Part of res/layout/buttons.xml)
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showToggleButtonInfo"/>
<ToggleButton
android:textOn="@string/ssl_toggle_on"
android:textOff="@string/ssl_toggle_off"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showToggleButtonInfo"/>
<ToggleButton
android:textOn="@string/gps_toggle_on"
android:textOff="@string/gps_toggle_off"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showToggleButtonInfo"/>
</LinearLayout>
56
No textOn or textOff attributes, so
the defaults of ON and OFF will be
used.
XML: Strings File Entries
(Part of res/values/strings.xml)
<string
<string
<string
<string
<string
name="ssl_toggle_on">Use SSL</string>
name="ssl_toggle_off">No SSL</string>
name="gps_toggle_on">GPS On</string>
name="gps_toggle_off">GPS Off</string>
name="toggle_button_message_template"
formatted="false">
You turned the ToggleButton %s.
Label is now \'%s\'.
</string>
The event handler method
will use String.format, this
template, the state of the
ToggleButton (on or off), and
the text to produce a
message that will be shown
in a Toast when a
ToggleButton is clicked.
57
Java (Relevant Parts)
public class ButtonActivity extends Activity {
private String mToggleButtonMessageTemplate;
@Override
public void onCreate(Bundle savedInstanceState) {
...
mToggleButtonMessageTemplate =
getString(R.string.toggle_button_message_template);
}
58
Java
(Relevant Parts, Continued)
This is the method specified for the
ToggleButtons via the android:onClick
attribute in the layout file.
public void showToggleButtonInfo(View clickedToggleButton) {
ToggleButton toggleButton =
(ToggleButton)clickedToggleButton;
String status;
if (toggleButton.isChecked()) {
status = "ON";
} else {
status = "OFF";
}
CharSequence label = toggleButton.getText();
String message =
String.format(mToggleButtonMessageTemplate,
status, label);
showToast(message);
}
59
Results (Emulator)
60
Wrap-Up
Summary
• Click handling is consistent among buttons
– Button, ImageButton, RadioButton, CheckBox, ToggleButton
• Can specify event handler method with android:onClick
• Or can set programmatically as in events lecture
• ImageButton
– Can have single image or set of three.
• Specify with android:src
• Images and image XML files go in res/drawable folder
• RadioGroup
– Surrounds RadioButtons. Can have its own Listener if you need to track
previous selection.
• ToggleButton
– Similar behavior to CheckBox. But
android:textOff instead of a fixed label.
62
has
android:textOn
and
Widgets: Spinners
(Combo Boxes)
Originals of Slides and Source Code for Examples:
http://www.coreservlets.com/android-tutorial/
Topics in This Section
• Switching from one Activity to another
• Spinners with choices set in XML
• Spinners with choices set in Java
64
General Approach
for Widget Examples
Widget Lectures Combined in Single Project
• Main screen
– Lets user choose screens on various Widget topics
• Other screens
– Correspond to separate lectures.
• One screen for lecture on Buttons, another for lecture on Spinners,
another for number input, etc.
• Separate layout files
– main.xml, buttons.xml, spinners.xml, etc. See next slide.
• Separate Java classes
– WidgetActivity.java, ButtonActivity.java, SpinnerActivity.java, etc.
• Shared strings file
– strings.xml has separate sections for each lecture, but same file
66
Layout Files for Widget Lectures
• Separate layout files for each Activity
– res/layout/main.xml
• Gives
layout
for
main
setContentView(R.layout.main);
screen.
Loaded
with
– res/layout/buttons.xml
• Gives layout for screen on Button and related Widgets. Loaded with
setContentView(R.layout.buttons);
– res/layout/spinners.xml
• Gives layout for screen on Spinners (i.e., combo boxes). Loaded with
setContentView(R.layout.spinners);
• Two common layout attributes
– android:layout_width, android:layout_height
• match_parent (fill up space in enclosing View)
• wrap_content (use natural size)
67
Strings File for Widget Lectures
(res/values/strings.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Initial screen -->
<string name="app_name">...</string>
<string name="show_buttons_button_label">...</string>
<string name="show_spinners_button_label">...</string>
<!-- Buttons example -->
<!-- Shown in earlier lecture -->
<!-- Spinners example -->
<!-- Shown in this lecture -->
...
</resources>
68
Switching Activities: Summary
• Switches Activities with Intents
– Main screen has buttons to navigate to other Activities
– Return to original screen with phone’s “back” button
• Syntax required to start new Activity
– Java
• Intent newActivity = new Intent(this, NewActivity.class);
• startActivity(newActivity);
– XML
• Requires entry in AndroidManifest.xml (which is part of downloadable
Eclipse project for Widgets)
– More details
• Code shown on next few slides
• Even more information given in later lecture on Intents
69
Switching Activities: Details
• Java (InitialActivity.java)
Intent newActivity = new Intent(this, NewActivity.class);
startActivity(newActivity);
• XML (AndroidManifest.xml)
<activity android:name=".NewActivity"
android:label="@string/new_app_name">
<intent-filter>
<action
android:name="android.intent.action.VIEW" />
The intent-filter part stays the same. Just copy and paste.
<category
android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
70
Switching Activities:
WidgetsInitialActivity.java
public class WidgetsInitialActivity extends
Activity {
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
private void goToActivity
(Class<? extends Activity>
activityClass) {
Intent newActivity = new Intent(this,
activityClass);
startActivity(newActivity);
}
public void showSpinners(View clickedButton)
{
goToActivity(SpinnerActivity.class);
}
...
}
71
If you have never seen wildcards in generics before,
this just means that I will pass in a subclass of Activity
(as with SpinnerActivity.class at bottom).
Switching Activities: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.coreservlets.widgets"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".WidgetsInitialActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
...
<activity android:name=".SpinnerActivity"
android:label="@string/spinner_app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
72
Most parts of this file were created automatically when the Android
project was made in Eclipse. To switch Activities yourself, cut and
paste this code from the downloadable source, and change only
android:name and android:label.
Overall Widget Project Layout
Java code
Images and XML files that refer to sets of images.
The layout files will refer to these images via
@drawable/base_file_name (e.g., @drawable/gps).
See ImageButton examples in lecture on buttons.
Layout files. The Java code will refer to the overall layouts via
R.layout.base_file_name (R.layout.main, R.layout.spinners, etc.).
The Java code will refer to specific GUI elements with
findViewById(R.id.element_id).
Strings. The Java code will refer to these via
getString(R.string.string_name). The layout files will refer to these
with @string/string_name. You can also define arrays of strings
here, or put the arrays in a separate file typically called arrays.xml.
Arrays defined here are used in the first Spinner example.
73
In order for one Activity to start another Activity in the same project, you need
some entries in here. See upcoming slide.
Spinner Approach 1:
Choices Specified in XML
Spinner with Predefined Choices
• Idea
– A combo box (drop down list of choices)
• Similar purpose to a RadioGroup: to let the user choose among a fixed
set of options
• Main Listener types
– AdapterView.OnItemSelectedListener
– AdapterView.OnItemClickedListener
• The first is more general purpose, since it will be invoked on
programmatic changes and keyboard events as well as clicks.
75
Spinner (Continued)
• Key XML attributes
– android:id
• You need a Java reference to assign an event handler
– android:prompt
• The text shown at the top of Spinner when user clicks to open it.
– Since text is not shown when the Spinner is closed, the string used for the
prompt is typically also displayed in a TextView above the Spinner.
– android:entries
• An
XML
entry
defining
an
array
of
Can be in strings.xml or a separate file (e.g., arrays.xml)
<string-array name="some_name">
<item>choice 1</item>
<item>choice 2</item>
…
</string-array>
76
choices.
OnItemSelectedListener
• onItemSelected
– Invoked when the an entry is selected. Invoked once when Spinner
is first displayed, then again for each time the user selects
something.
– Arguments
• AdapterView: the Spinner itself
• View: the row of the Spinner that was selected
• int: the index of the selection. Pass this to the Spinner’s
getItemAtPosition method to get the text of the selection.
• long: The row id of the selected item
• onNothingSelected
– Invoked when there is now nothing displayed. This cannot happen
due to normal user interaction, but only when you
programmatically remove an entry.
77
XML: Layout File Entry
(Part of res/layout/spinners.xml)
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/spinner1_prompt"/>
<Spinner
android:id="@+id/spinner1"
android:prompt="@string/spinner1_prompt"
android:entries="@array/spinner1_entries"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Same text used twice,
since the text is hidden
when the Spinner is
closed.
An array of entries. If you
have lots of arrays, you
typically put them in
arrays.xml. However, here,
it makes more sense to
keep the array of entries in
strings.xml with the
spinner prompt and the
spinner message
template.
78
XML: Strings File Entries
(Part of res/values/strings.xml)
<string name="spinner1_prompt">
Current Android Vendors (Choices from XML)
</string>
<string-array name="spinner1_entries">
<item>Acer</item>
<item>Dell</item>
<item>HTC</item>
<item>Huawei</item>
<item>Kyocera</item>
<item>LG</item>
<item>Motorola</item>
<item>Nexus</item>
<item>Samsung</item>
<item>Sony Ericsson</item>
<item>T-Mobile</item>
<item>Neptune</item>
</string-array>
<string name="spinner_message_template">
You selected \'%s\'.
</string>
79
The event handler method
will use String.format, this
template, and the current
selection to produce a
message that will be shown
in a Toast when a Spinner
selection is made.
Java (Relevant Parts)
public class SpinnerActivity extends Activity {
private String mItemSelectedMessageTemplate;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spinners);
mItemSelectedMessageTemplate =
getString(R.string.spinner_message_template);
Spinner spinner1 = (Spinner)findViewById(R.id.spinner1);
spinner1.setOnItemSelectedListener(new SpinnerInfo());
... // Code for spinner2 shown later
}
private void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
}
// Continued on next slide with the SpinnerInfo inner class
80
Java
(Relevant Parts, Continued)
private class SpinnerInfo implements OnItemSelectedListener {
private boolean isFirst = true;
@Override
public void onItemSelected(AdapterView<?> spinner, View selectedView,
int selectedIndex, long id) {
if (isFirst) {
isFirst = false;
Don't want the Toast when the screen is first
} else {
displayed, so ignore the first call to onItemSelected.
String selection =
Other calls are due to user interaction.
spinner.getItemAtPosition(selectedIndex).toString();
String message =
String.format(mItemSelectedMessageTemplate, selection);
showToast(message);
}
}
@Override
public void onNothingSelected(AdapterView<?> spinner) {
// Won’t be invoked unless you programmatically remove entries
}
}
81
Results (Emulator)
82
Spinner Approach 2:
Choices Specified in Java
Spinner with Choices Computed by Java Code
• Idea
– A combo box (drop down list of choices)
• Same general purpose as previous example. However, here you want to
programmatically compute the options to be displayed, possibly based
on earlier user interaction.
• Main Listener types
– AdapterView.OnItemSelectedListener
– AdapterView.OnItemClickedListener
• These are same as in previous Spinner example
84
Spinner (Continued)
• Key XML attributes
– android:id
• You need a Java reference to specify the entries and to assign an event
handler.
– android:prompt
• The text shown at the top of Spinner when user clicks to open it.
– Since this text is not shown when the Spinner is closed, the string used for
the prompt is typically also displayed in a TextView above the Spinner.
– android:entries
• Not used in this version. Java will compute the entries.
85
Creating Spinner Entries Programmatically
• Get reference to the Spinner
Spinner spinner = (Spinner)findViewById(R.id.spinner_id);
• Make an ArrayAdapter
List<String> entries = …; // Can also use String[]
ArrayAdapter<String> spinnerAdapter =
new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item,
entries);
• Specify the drop down View resource
spinnerAdapter.setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
• Set the adapter for the Spinner
spinner.setAdapter(spinnerAdapter);
86
Predefined
entry in Android
distribution
XML: Layout File Entry
(Part of res/layout/spinners.xml)
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/spinner2_prompt"/>
<Spinner
android:id="@+id/spinner2"
android:prompt="@string/spinner2_prompt"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Same text used twice,
since the text is hidden
when the Spinner is
closed.
android:entries is not
used. Instead of having
fixed choices, the Java
code will compute the
options.
87
XML: Strings File Entries
(Part of res/values/strings.xml)
<string name="spinner2_prompt">
Future Android Vendors (Choices from Java)
</string>
88
Java (Relevant Parts)
public class SpinnerActivity extends Activity {
private String mItemSelectedMessageTemplate;
@Override
public void onCreate(Bundle savedInstanceState) {
// General code and code for spinner1 shown earlier
List<String> futureAndroidVendors =
getFutureAndroidVendors();
ArrayAdapter<String> spinner2Adapter =
new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item,
futureAndroidVendors);
spinner2Adapter.setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
spinner2.setAdapter(spinner2Adapter);
spinner2.setOnItemSelectedListener(new SpinnerInfo());
}
89
Java
(Relevant Parts, Continued)
private List<String> getFutureAndroidVendors() {
String[] vendorArray = { "Apple", "RIM",
"Palm", "Microsoft" };
List<String>
vendorList
Arrays.asList(vendorArray);
Collections.shuffle(vendorList);
return(vendorList);
}
The last argument to the ArrayAdapter<String>
constructor on previous page can be any
List<String> or String[]. I am randomizing the
order of the elements to demonstrate that you
can have Java compute the entries instead of
having a fixed set of choiuces (in which case
you would define the entries in the XML file as
with approach 1).
90
=
Results (Emulator)
91
Wrap-Up
Summary
• Spinner with fixed entries
– Define array in strings.xml.
– Use android:prompt and android:entries in layout file. Also assign
id with android:id
– Java gets ref and calls setOnItemSelectedListener
• Spinner with computed entries
– XML uses android:prompt and android:id
– Java gets ref, makes ArrayAdapter with a List<String> or String[],
uses some predefined resource names
• Switching Activities
– Intent newActivity = new Intent(this, NewActivity.class);
– startActivity(newActivity);
– Also requires entry in AndroidManifest.xml
93
Android Programming:
Widget Event Handling
Originals of Slides and Source Code for Examples:
http://www.coreservlets.com/android-tutorial/
Topics in This Section
•
•
•
•
Using a separate Listener class
Using a named inner class
Using an anonymous inner class
Using the main Activity
– And having it implement the Listener interface
• Using the main Activity
– And specifying the method in the layout file (main.xml)
• Copying and renaming Eclipse Android projects
95
Using a Separate Listener Class
Idea
• Goal
– Change color of a TextView when Button or RadioButton is pressed.
Different colors depending on which pressed.
• Approach
– Use an external class that implements View.OnClickListener
• Import android.view.View.OnClickListener,
OnClickListener”
then
say
“implements
• Advantages
– You can pass arguments to change behavior
– Separate classes generally promote loose coupling
• So, if event handler can be applied to different controls, it can be change
independently from rest of app.
– But, in most real situations, behavior is tightly coupled to app anyhow.
• Disadvantages
– If you want to call code in main Activity, you need reference
– Even then, that code in main Activity must be public
97
Summary of Layout
Button
Button
Button
Horizontal RadioGroup
(Containing 3 RadioButtons)
Vertical
LinearLayout
TextView
(No text, but controls will
change the background
color of this region.)
98
An upcoming tutorial section gives details on using layouts. However,
you can do a pretty lot now by knowing just two simple things:
1)
You can make some pretty complex layouts by nesting horizontal
and vertical layouts inside each other.
2)
You can experiment interactively with the visual layout editor in
Eclipse. Edit main.xml and click on Graphical Layout.
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
Overall layout is a vertical stack of graphical items.
<Button
android:id="@+id/button1"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/red_prompt"/>
<Button
android:id="@+id/button2"
This part defines the 3 buttons shown on the previous slide.
android:layout_height="wrap_content"
android:layout_width="match_parent"
Each button is given an id so that it can be found in Java via
findViewById, then assigned an event handler via
android:text="@string/blue_prompt"/>
setOnClickListener.
<Button
The text (Button label) is taken from strings.xml instead of
android:id="@+id/button3"
entered directly here, because the same label will also be
android:layout_height="wrap_content"
used for RadioButtons.
android:layout_width="match_parent"
android:text="@string/yellow_prompt"/>
99
res/layout/main.xml (Continued)
<RadioGroup
android:gravity="center_horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radio_button1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/red_prompt"/>
<RadioButton
android:id="@+id/radio_button2"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/blue_prompt"/>
<RadioButton
android:id="@+id/radio_button3"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/yellow_prompt"/>
</RadioGroup>
100
A horizontal RadioGroup gives the same layout
as a horizontal LinearLayout, except that it
contains only RadioButtons. A RadioGroup also
means that only one of the RadioButtons inside
can be selected at any given time.
res/layout/main.xml (Continued)
<TextView
android:id="@+id/color_region"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</LinearLayout>
This defines the blank region at the bottom that
will change colors when the Buttons or
RadioButtons are clicked. I used a TextView
because I might later want to put some text
inside.
101
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Event Handling Example</string>
<string name="red_prompt">Red</string>
<string name="blue_prompt">Blue</string>
<string name="yellow_prompt">Yellow</string>
</resources>
main.xml refers to these names with @string/red_prompt,
@string/blue_prompt, and @string/yellow_prompt.
Each string is used as label for one Button and one RadioButton.
102
Main Activity Class
public class Events1Example extends Activity {
private View mColorRegion;
This part just looks up the
controls that were defined in
main.xml, and assigns them to
variables. Note the Android
coding convention that non-public
instance variables (data
members) start “m”.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mColorRegion = findViewById(R.id.color_region);
Button b1 = (Button)findViewById(R.id.button1);
Button b2 = (Button)findViewById(R.id.button2);
Button b3 = (Button)findViewById(R.id.button3);
RadioButton r1 =
(RadioButton)findViewById(R.id.radio_button1);
RadioButton r2 =
(RadioButton)findViewById(R.id.radio_button2);
RadioButton r3 =
(RadioButton)findViewById(R.id.radio_button3);
103
Main Activity Class (Continued)
b1.setOnClickListener(new
b2.setOnClickListener(new
b3.setOnClickListener(new
this));
r1.setOnClickListener(new
r2.setOnClickListener(new
r3.setOnClickListener(new
this));
}
ColorSetter(Color.RED, this));
ColorSetter(Color.BLUE, this));
ColorSetter(Color.YELLOW,
ColorSetter(Color.RED, this));
ColorSetter(Color.BLUE, this));
ColorSetter(Color.YELLOW,
public void setRegionColor(int color) {
mColorRegion.setBackgroundColor(color);
}
}
104
Since this method will be
called by method in
separate event handler
class, it must be public.
Assigns a separate class as the event
handler for each of the Buttons and
RadioButtons.
Good news: you can pass arguments
to the event handler (the colors) so that
the same event handler class can have
different behaviors for different controls.
Bad news: you have to pass a
reference to the main Activity (“this”
above) so that the event handler can
call back to code in the Activity.
Event Handler Class
public class ColorSetter implements OnClickListener {
private int regionColor;
private Events1Example mainActivity;
public ColorSetter(int regionColor,
Events1Example mainActivity) {
this.regionColor = regionColor;
this.mainActivity = mainActivity;
}
@Override
public void onClick(View v) {
mainActivity.setRegionColor(regionColor);
}
}
105
Event handler must store a reference to the main Activity so that it can call
back to it. Another option in this particular case would be to pass the TextView
to the event handler, but passing the main Activity is a more general solution.
Results on Emulator
106
Results on Physical Phone
107
Using a Named Inner Class for
Event Handling
Idea
• Goal
– Change color of a TextView when Button or RadioButton is pressed.
Different colors depending on which pressed.
• Same as previous example
• Approach
– Use an inner class that implements View.OnClickListener
• Advantages
– You can pass arguments to change behavior
– Event handler methods can access private data of Activity. No
reference is needed to call to Activity.
• Disadvantages
– Since Listener class is in same file as Activity, it is more tightly
coupled, and cannot be changed independently
109
XML Files:
Same as Previous Example
• res/layout/main.xml
– Defines vertical LinearLayout that contains 3 Buttons, a horizontal
RadioGroup (with 3 RadioButtons), and a TextView.
– The Buttons, RadioButtons, and TextView have ids so that they can
be referred to in the Java code
• res/values/strings.xml
– Defines the app name and the labels of the Buttons and
RadioButtons
110
Main Activity Class
public class Events2Example extends Activity {
private View mColorRegion;
Except for the class name, this
top part of the Activity is exactly
the same as the previous
example.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mColorRegion = findViewById(R.id.color_region);
Button b1 = (Button)findViewById(R.id.button1);
Button b2 = (Button)findViewById(R.id.button2);
Button b3 = (Button)findViewById(R.id.button3);
RadioButton r1 =
(RadioButton)findViewById(R.id.radio_button1);
RadioButton r2 =
(RadioButton)findViewById(R.id.radio_button2);
RadioButton r3 =
(RadioButton)findViewById(R.id.radio_button3);
111
Main Activity Class (Continued)
b1.setOnClickListener(new
b2.setOnClickListener(new
b3.setOnClickListener(new
r1.setOnClickListener(new
r2.setOnClickListener(new
r3.setOnClickListener(new
ColorSetter(Color.RED));
ColorSetter(Color.BLUE));
ColorSetter(Color.YELLOW));
ColorSetter(Color.RED));
ColorSetter(Color.BLUE));
ColorSetter(Color.YELLOW));
}
private void setRegionColor(int color) {
mColorRegion.setBackgroundColor(color);
}
Since this method will only
be called by method in inner
event handler class, it is
allowed to be private.
Note no closing brace. This class
is not finished yet (continued on
next slide)
112
Assigns an inner class as the event
handler for each of the Buttons and
RadioButtons.
As with the previous example, you can
pass arguments to the event handler
(the colors) so that the same event
handler class can have different
behaviors for different controls.
However, since the event handler is in
the same class, you do not have to
supply a reference to the main Activity
class.
Event Handler Class
(Part of Main Activity Class)
private class ColorSetter implements OnClickListener {
private int regionColor;
public ColorSetter(int regionColor) {
this.regionColor = regionColor;
}
@Override
public void onClick(View v) {
setRegionColor(regionColor);
}
}
}
Event handler can directly call methods in the main
Activity, even if the method is private.
Closes off the main Activity class.
113
Results on Emulator
Same as previous example.
114
Results on Physical Phone
Same as previous example.
115
Using an Anonymous Inner
Class for Event Handling
Idea
• Goal
– Randomly change color of TextView when Button is pressed.
• Approach
– Use an anonymous inner class that implements the Listener
• Advantages
– Assuming that each class is applied to a single control only, same
advantages as named inner classes, but shorter.
• This approach is widely used in Swing, SWT, AWT, and GWT.
• Disadvantages
– If you applied the handler to more than one control, you would have to
cut and paste the code for the handler.
• This approach should be applied for a single control only
– If the code for the handler is long, it makes the code harder to read by
putting it inline.
• This approach is usually used only when handler code is short
117
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/color_button"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/button_prompt"/>
<TextView
android:id="@+id/color_region"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</LinearLayout>
118
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Event Handling Example</string>
<string name="button_prompt">Random Color</string>
</resources>
119
Main Activity Class Attempt 1:
Named Inner Class
public class Events3Example extends Activity {
private View mColorRegion;
private int[] mColorChoices =
{ Color.BLACK, Color.BLUE, ...};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mColorRegion = findViewById(R.id.color_region);
Button colorButton =
(Button)findViewById(R.id.color_button);
colorButton.setOnClickListener(new ColorRandomizer());
}
private void setRegionColor(int color) {
mColorRegion.setBackgroundColor(color);
}
120
There is nothing wrong with this approach.
However, this event handler class is only
used on this line of code. Furthermore, the
code for ColorRandomizer (next page) is
relatively short. So, you can make it a bit
more concise with an anonymous inner
class.
Main Activity Class Attempt 1:
Named Inner Class (Continued)
private
class
ColorRandomizer
implements OnClickListener {
@Override
public void onClick(View v) {
Random generator = new Random();
int
index
=
generator.nextInt(mColorChoices.length);
setRegionColor(mColorChoices[index]);
}
}
}
121
Main Activity Class Refactored:
Anonymous Inner Class
public class Events3Example extends Activity {
private View mColorRegion;
private int[] mColorChoices =
{ Color.BLACK, Color.BLUE, ...};
private void setRegionColor(int color) {
mColorRegion.setBackgroundColor(color);
}
See next page for onCreate
122
Main Activity Class Refactored:
Anonymous Inner Class (Cont.)
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mColorRegion = findViewById(R.id.color_region);
Button colorButton =
(Button)findViewById(R.id.color_button);
colorButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Random generator = new Random();
int
index
generator.nextInt(mColorChoices.length);
=
setRegionColor(mColorChoices[index]);
}
});
}
123
This defines the class and instantiates it all in one fell swoop. If you have never seen anonymous
inner classes before, the confusion is probably not worth the code savings over a named inner
class. However, once you are used to it, it is more concise and arguably easier to understand
because the behavior is shown where it is used. This approach is very commonly used by Swing,
SWT, AWT, and GWT programmers. This is also very analogous to anonymous functions
(closures) that are widely used in functional programming languages.
Results on Emulator
124
Results on Physical Phone
125
Handling Events by Having Main
Activity Implement Listener
Interface
Idea
• Goal
– Randomly change color of TextView when Button is pressed.
• Same as previous example
• Approach
– Have the main Activity implement the Listener interface. Put the handler
method in the main Activity. Call setOnClickListener(this).
• Advantages
– Assuming that the app has only a single control of that Listener type, this is the
shortest and simplest of the approaches.
• Disadvantages
– Scales poorly to multiple controls unless they have completely identical
behavior.
• If you assigned “this” as the handler for more than one control of the same Listener
type, the onClick (or whatever) method would have to have cumbersome if
statements to see which control was clicked
• This approach should be applied when your app has only a single control of that
Listener type
– You cannot pass arguments to the Listener.
• So, again, works poorly for multiple controls
127
XML Files:
Same as Previous Example
• res/layout/main.xml
– Defines vertical LinearLayout that contains a Button and a
TextView.
– The Button and TextView have ids so that they can be referred to in
the Java code
• res/values/strings.xml
– Defines the app name and the label of the Button
128
Main Activity Class
public class Events5Example extends Activity
implements OnClickListener {
private View mColorRegion;
private int[] mColorChoices =
{ Color.BLACK, Color.BLUE, ... };
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mColorRegion = findViewById(R.id.color_region);
Button colorButton =
(Button)findViewById(R.id.color_button);
colorButton.setOnClickListener(this);
}
129
Main Activity Class (Continued)
private void setRegionColor(int color) {
mColorRegion.setBackgroundColor(color);
}
@Override
public void onClick(View v) {
Random generator = new Random();
int index = generator.nextInt(mColorChoices.length);
setRegionColor(mColorChoices[index]);
}
}
130
Results on Emulator
Same as previous example.
131
Results on Physical Phone
Same as
previous
example.
132
Handling Events by Specifying
the Event Handler Method in
main.xml
Idea
•
Goal
–
Randomly change color of TextView when Button is pressed.
•
•
Approach
–
•
–
–
Assuming that the app has only a single control of that Listener type, mostly the same
advantages (short/simple code) as the previous approach where the Activity implemented the
interface.
More consistent with the “do layout in XML” strategy
You can supply different method names for different controls, so not nearly as limited as
interface approach.
Disadvantages
–
–
–
134
Put the handler method in the main Activity. Do not implement a Listener interface or call
setOnClickListener. Have the layout file (main.xml) specify the handler method via the
android:onClick attribute.
Advantages
–
•
Same as previous example
You cannot pass arguments to Listener.
Less clear to the Java developer which method is the handler for which control
Since no @Override, no warning until run time if method is spelled wrong or has wrong
argument signature
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/color_button"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/button_prompt"
android:onClick="randomizeColor"/>
<TextView
android:id="@+id/color_region"
android:layout_height="match_parent"
This is the name of the event
handler method in the main class.
android:layout_width="match_parent"/>
This method must have a void
</LinearLayout>
return type and take a View as an
135
argument. However, the method
name is arbitrary, and the main
class need not implement any
particular interface.
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Event Handling Example</string>
<string name="button_prompt">Random Color</string>
</resources>
Unchanged from the previous two examples
136
Main Activity Class
public class Events6Example extends Activity {
private View mColorRegion;
private int[] mColorChoices =
{ Color.BLACK, Color.BLUE, ... };
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mColorRegion = findViewById(R.id.color_region);
// No need to look up the button or assign event
handler
}
137
Main Activity Class (Continued)
private void setRegionColor(int color) {
mColorRegion.setBackgroundColor(color);
}
public void randomizeColor(View v) {
Random generator = new Random();
int index = generator.nextInt(mColorChoices.length);
setRegionColor(mColorChoices[index]);
}
}
Matches method name given for
android:onClick in main.xml
138
Results on Emulator
Same as previous example.
139
Results on Physical Phone
Same as
previous
example.
140
Aside: Copying Android
Projects in Eclipse
Steps to Copy Projects
• Issues
– The projects in this tutorial are very similar to each other.
• So, you want to copy/rename previous project instead of making new
project and copying many separate pieces
• But, package names on devices must be unique
• Renaming package requires care. Poor Eclipse support.
• Steps (order of steps 2 and 3 matter!)
1.
2.
3.
4.
142
R-click old project. R-click and choose Paste. New name.
R-click new project, Android Tools  Rename Application
Package. New name. Unselect the Java classes, and leave selection
for manifest only. OK when asked to update launch configuration.
R-click src/projectName in new project. Refactor  Rename. OK
when warned package exists.
Optional: R-click main Activity. Refactor  Rename.
Wrap-Up
Approaches: Single or Multiple Controls
• Situation
– Same handler code may be applied to multiple controls
• Options
– Use a separate event handler class
• Pros: can pass args to handler to customize behavior, easier to change
independently of main app
• Cons: if handler will call code in main Activity, must pass “this” and
must make methods public
– Use a named inner class
• Pros: can pass args to handler to customize behavior, no need to pass
“this” reference, methods can be private
– This is my overall favorite and most widely used approach for Widget
event handling
• Cons: handler tightly coupled to main Activity
144
Approaches: Single Control
• Situation
– Handler code will be applied only to a single control
• Options
– Use an anonymous inner class
• Pros: same as named inner class, but more concise
• Cons: confusing to newbies or if handler code is long
– Put handler method in
call setOnClickListener(this)
Activity,
implement
interface,
• Pros: simple code
• Cons: can’t pass arguments to handler class
– Put
handler
method
in
Activity,
no
specify method with android:onClick in main.xml
interface,
• Pros: one method per control, but can specify different methods for
each control. More XML-oriented. Less Java code.
• Cons: more confusing to Java developer (arguably)
145
Ευχαριστώ για την προσοχή σας!