In This Chapter
• The Role of Android Application Components
• The Utility of the Android API
• An Overview of Android Project Files
• An Introduction to Activities and the Android Activity Life Cycle
• The Role of Android Manifest Files
• How to Create the User Interface
• Commonly Used Layouts and Controls
• How to Create an Anonymous Inner Class
• The Activity Implementing the OnClickListener
interface
• How to Display Messages Through Toast
• How to Declare the Event Handler in the XML Definition of the Control
• How to Create Your Own Layout File
• How to Create, Register, and Start a New Activity
• How to Use the EditText
, Checkbox
, and RadioButton
Controls
Almost all popular applications are interactive. These applications interact with the user, and, depending on the data supplied by the user, desired actions and/or processing are performed. The user interface controls thus play a major role in getting feedback from the user. In this chapter, we learn about the basic widgets supplied by the Android SDK for creating simple user interfaces. In later chapters, we learn about complex widgets for creating sophisticated user interfaces. Also, for better understanding of the Android application, we discuss different Android Project files and Activities
that are automatically created for us by the Android Eclipse plug-in to reduce the work needed to develop an Android application.
To gain an understanding of the role and functionality of different components that make up an Android application, you create a new Android application and study each of its components.
Let’s start by creating an application that prompts the user to enter a name and displays a Welcome message in return. The Android Project Wizard creates all the required files for an Android application. To create an application, open Eclipse and choose, File
, New
, Android Application Project
or click the Android Project Creator icon on the Eclipse toolbar. You see a dialog box, as shown in Figure 2.1 (left).
• In the Application Name
box, enter the name of the Android project. Let’s name the application WelcomeMsg
. The Project Name
is automatically assigned, which is the same as the application name by default. Being a unique identifier, the Package Name
is com.androidunleashed.welcomemsg
.
• From the Build SDK
drop-down, select Android 4.1 (API 16)
as the target platform as we expect it to be the version commonly used by your target audience.
• Select API 8: Android 2.2 (Froyo)
from the Minimum Required SDK
drop-down to indicate that the application requires at least API level 8 to run.
• Because this is a new project, select the Create Project in Workspace
check box to create the project files at the Workspace location specified when opening Eclipse for the first time. The Create custom launcher icon
check box is selected by default and enables us to define the icon of our application. Click the Next
button to move to the next dialog box.
• The next dialog is Configure Launcher Icon,
which is meant for configuring the icon for the application. Because we want to have a default icon for our application, keeping the default options selected in the dialog box, click the Next
button to move further.
• The next dialog prompts us to select whether we want to create an activity. Also, it prompts for the type of activity. Because we want to create a blank activity, select the Create Activity
check box and the BlankActivity
option from the list and then click Next
.
• The next dialog (see Figure 2.1—right) asks us to enter information about the newly created activity. Name the activity WelcomeMsgActivity
. The layout filename and title name automatically change to reflect the newly assigned activity name. The layout name becomes activity_welcome_msg
, and the Title
of the application also changes to WelcomeMsgActivity
. We can always change the auto-assigned layout filename and title of the application.
• Keeping the auto-assigned layout filename and the title unchanged, click the Finish
button after supplying the required information. The application is created by ADT, along with all the necessary files.
The Android platform provides a framework API that applications can use to interact with the underlying Android system. The framework API consists of a core set of packages and classes; XML elements for declaring layouts, resources, and so on; a manifest file to configure applications; permissions that applications might require; intents; and much more. The framework API is specified through an integer called API level, and each Android platform version supports exactly one API level, although backward compatibility is there; that is, earlier API levels are supported. The initial release of the Android platform provided API Level 1, and subsequent releases have incremented the API level.
Table 2.1 shows the API level supported by each version of the Android platform.
Each Android API level shows the maximum framework API revision that the Android platform supports. You need to select the Target Name, and hence the API level for the application, as doing so helps the application specify the framework API revision it requires to operate.
Remember that to enable applications to run on a maximum number of platforms, you can set the applications to target the lowest platform, Android 1.0. Because of backward compatibility, the application that supports the Android 1.0 platform can easily run on all the devices, even on the devices with the Android 4.0 platform. However, the opposite is not true. There is a cost to selecting the lowest platform too: you cannot use features supported in higher platforms. Thus, all the applications that you create in this book target platform 4.1 to exploit the latest features added to the API.
After creating the new Android application by name, WelcomeMsg
, the ADT creates a WelcomeMsg
directory in the default Eclipse workspace for the project. It also creates subdirectories for keeping source files, compiled or generated files, resource files, and so on. Certain default content is also created in these subdirectories that are required in an Android application. Several files, such as AndroidManifest.xml
and project.properties
, are also automatically created to make the job of configuring the Android application easier. You can have a look at the files and directories created by ADT if you expand the project tree in the Package Explorer
window (see Figure 2.2).
Let’s take a quick look at the different folders and files created by ADT.
The following files and directories are created for the Android application. The list below is just an overview of the files and directories. We will talk about these files and directories in detail as we move further in the book:
• /src
folder—The folder that contains the entire Java source file of the application. The folder contains a directory structure corresponding to the package name supplied in the application. The folder contains the project’s default package: com.androidunleashed.welcomemsg
. On expanding the package, you find the Activity of the application, the WelcomeMsgActivity.java
file, within it.
• /src/com.androidunleashed.welcomemsg—Refers to the package name of the application. To avoid any collision among the class names, variable names, and so on used in the application with those of other Android applications, each application has to be packaged in a unique container.
• /src/com.androidunleashed.welcomemsg/WelcomeMsgActivity.java—The default Activity file of the application. Recall that each application has at least one Activity that acts as the main entry point to the application. The Activity file is automatically defined as the default launch Activity in the Android Manifest file.
• /gen
folder—Contains Java files generated by ADT on compiling the application. That is, the gen
folder will come into existence after compiling the application for the first time. The folder contains an R.java
file that contains references for all the resources defined in the res
directory. It also contains a BuildConfig.java
file that is used to run code only in debug mode. It contains a DEBUG
constant that helps in running debug-only functions.
• /gen/com.androidunleashed.welcomemsg/R.java—All the layout and other resource information that is coded in the XML files is converted into Java source code and placed in the R.java
file. It also means that the file contains the ID of all the resources of the application. The R.java
file is compiled into the Java byte code files and then converted into .dex
format. You should never edit this file by hand, as it is automatically overwritten when you add or edit resources.
• Android SDK jar
file—The jar
file for the target platform.
• /assets
folder—The assets
folder is empty by default. It stores raw asset files that may be required in the application. It may contain fonts, external JAR files, and so on to be used in the application. The assets
folder is like a resource folder where uncompiled resources of the project are kept and no IDs are generated for the resources kept here.
• /bin
folder—The folder that stores the compiled version of the application.
• /res
folder—The folder where all application resources (images, layout files, and string files) are kept. Instead of hard coding an image or string in an application, a better approach is to create a respective resource in the res
folder and include its reference in the application. This way, you can change the image or string or any other resource anytime without disturbing the code. Each resource is assigned a unique resource ID, which automatically appears in the R.java
file and thus in the R
class after compilation, enabling us to refer to the resource in the code. To categorize and arrange the resources, three subdirectories are created by default: drawable
, layout
, and values
.
• /res/drawable-xhdpi
, /res/drawable-hdpi
, /res/drawable-mdpi
, /res/drawable-ldpi
—the application’s icon and graphic resources are kept in these folders. Because devices have screens of different densities, the graphics of different resolutions are kept in these folders. Usually, graphics of 320dpi, 240dpi, 160dpi, and 120dpi are used in Android applications. The graphics with 320dpi, 240dpi, 160dpi, and 120dpi are stored in the res/drawable-xhdpi
, res/drawable-hdpi/
, res/drawable-mdpi
, and res/drawable-ldpi
folders, respectively. The application picks up the graphic from the correct folder after determining the density of the current device.
• /res/layout—Stores the layout file(s) in XML format.
• /res/values—Stores all the values resources. The values resources include many types such as string resource, dimension resource, and color resource.
• /res/layout/activity_welcome_msg.xml—The layout file used by WelcomeMsgActivity
to draw views on the screen. The views or controls are laid in the specified layout.
• /res/values/strings.xml—Contains the string resources. String resources contain the text matter to be assigned to different controls of the applications. This file also defines string arrays.
• AndroidManifest.xml—The central configuration file for the application.
• proguard.cfg—Defines how ProGuard optimizes the application’s code. ProGuard is a tool that removes unused code from the Android application and optimizes it, which increases performance. It is also used to obfuscate the code to help protect it from decompilation.
• project.properties—A build file used by Eclipse and the Android ADT plug-in. It contains project settings such as the build target. You can use this file to change various properties of the project. If required, the file should not be edited directly but through editors available in Eclipse.
Other folders that may become the part of an Android application include bin
, libs
, and referenced libraries
. The bin
folder is hidden. The libs
and referenced libraries
folders don’t appear until a third-party library and reference are added to the project.
It’s clear that the Java Activity file is the main file that drives the entire Android application. The default content of the Activity file WelcomeMsgActivity.java
is shown in Listing 2.1.
package com.androidunleashed.welcomemsg;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class WelcomeMsgActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome_msg);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_welcome_msg, menu);
return true;
}
}
Every unique screen the user interacts with in an application is displayed through an Activity—one Activity for each screen. Users can interact with an application by performing different actions with the visual controls found in the Activity. A simple application may consist of just one Activity, whereas large applications contain several Activities. Each Activity of an application operates independently of the others. A stack of Activities is maintained while running an application, and the Activity at the top of the stack is the one currently being displayed. When the Back
button is pressed, the Activity is popped from the stack, making the previous Activity the current Activity, which therefore displays the previous screen. The transition from one Activity to another is accomplished through the use of asynchronous messages called intents
. Intents can be used to pass data from one Activity to another. All of the Activities in the application must be defined in the Application’s manifest file, an XML file that keeps track of all the components and permissions of the application. Each Activity in an Android application is either a direct subclass of the Activity
base class or a subclass of an Activity
subclass.
Activities have life cycles and inherit a set of life cycle methods from the Activity
base class that are executed when the corresponding life cycle state of the Activity is reached.
The Android Activity life cycle defines the states or events that an Activity goes through from the time it is created until it finishes running. The Activity monitors and reacts to these events by executing methods that override the Activity
class methods for each event. Table 2.2 lists the methods executed during the different events that occur during an Android Activity life cycle.
All the activities of an application, permissions, and intents are defined through the XML-structured manifest file AndroidManifest.xml
. For each Activity, there needs to be an entry in the AndroidManifest.xml
file, where you can define labels, permissions, and so on. In fact, the manifest file is the configuration file where all the different components of the application are defined.
The configuration file AndroidManifest.xml
is created by ADT when creating a new Android project and is kept in the project’s root directory. It’s an XML file that defines the overall structure and information about the application, for example, the activities, services, and intents used in the application. It also contains the permissions that the application might need to run. The manifest also defines metadata of the application such as its icon and label. Besides this, the file also contains the information required in building and packaging the application for installing and deploying it on an Android device or the emulator. To sum up, the application manifest file contains all the essential information required by the Android system to run the application.
Note
Services refers to the processes that run in the background with no visual user interface. Services are used for the tasks that you want to run quietly in the background without user action and that supply some data or information to other applications. Services start when an Activity starts or when a device boots up, keeps running in the background, and stops automatically on finishing its task. Music playing in the background, a program displaying stock market figures, and a GPS tracking program that monitors the location of the device are few examples of services.
Listing 2.2 shows the manifest file for the application that you just created.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidunleashed.welcomemsg"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".WelcomeMsgActivity"
android:label="@string/title_activity_welcome_msg" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The <manifest>
tag, is the root element of this XML document and contains several attributes:
• android—Identifies the Android namespace used to provide several system attributes used within the application.
• package—Its value is set to the application’s Java package. The name of the application package acts as the unique identifier for the application in the Android device.
• versionCode
/versionName
—The versionCode
attribute is used to define the current application version. The version is used internally to compare application versions. The versionName
attribute is used to specify a version number that is displayed to users.
• <uses-sdk>—This tag is optional and is used to specify the maximum, minimum, and preferred API level required for the application to operate. Three attributes are used with this tag as follows:
• android:minSdkVersion—Used to specify the minimum API level required for this application to run. The default value is “1.” For example, the following attribute says that the minimum API level required by the application is 15:
android:minSdkVersion="15"
Hence, the application will run on API Level 15 and above, but will not run on API Level 14 or below.
• android:targetSdkVersion—Used to specify the preferred API level on which the application is designed to run.
• android:maxSdkVersion—Used to specify the maximum API level supportable by the application; that is, the application cannot run on an API level higher than the one specified in this attribute. While installing the application, the Android system checks the <uses-sdk>
attributes defined in the application’s manifest files and compares it with its own internal API level. The application can be installed only if
The value of the android:minSdkVersion
attribute of the application must be less than or equal to the system’s API level. If the android:minSdkVersion
attribute is not declared, it is assumed that the application requires API Level 1.
The value of the android:maxSdkVersion
attribute of the application (if it is declared) must be equal to, or greater than, the system’s API level.
• <application>
tag—Nested within <manifest>
is <application>
, which is the parent of application control tags. The icon
and label
attributes of the application
tag refer to icon and label resources that will be displayed in Android devices to represent the application. In Chapter 4, “Utilizing Resources and Media,” you learn about the resources in detail. For the time being, it is enough to understand that @string
and @drawable
refer to the strings and drawable resources, respectively. The term "@drawable/icon"
refers to the image file icon.png
in the res/drawable
folder, and "@string/app_name"
refers to the control resource with ID app_name
in the strings.xml
file that is stored in the res/values
folder of the application.
• <activity>
tag—Nested within <application>
is the <activity>
tag, which describes an Activity component. This tag’s name attribute identifies a class that is an Activity, WelcomeMsgActivity
. This name begins with a period character to show that it’s relative to the com.androidunleashed.welcomemsg
package. That is, the WelcomeMsgActivity
is relative to <manifest>
’s package value, com.androidunleashed.welcomemsg
. Remember that on creating the new Android project WelcomeMsg
, an Activity named WelcomeMsgActivity
was automatically created for us in the specified package com.androidunleashed.welcomemsg
by the ADT.
• <intent- filter>—Nested within <activity>
is the <intent-filter>.
The intents are used to interact with the applications and services. By default, the intent specifies the action as MAIN and the category as LAUNCHER; that is, it makes this Activity available from the application launcher, allowing it to launch when the application starts. Basically, the <intent-filter>
tag declares the capabilities of different components through the nested <action>
and <category>
tags.
Besides the preceding default tags used in the manifest file, the following are some of the most commonly used tags:
• <service>
tags—Used for declaring services. Services refer to the processes that run in the background without a user interface. They perform required processing and handle events silently without user interaction.
• <receiver>
tags—Used for declaring broadcast receivers. Broadcast receivers are used to listen and respond to broadcast announcements. Applications initiate broadcasts for the interested applications when some event occurs that requires attention; for example, essential information or confirmation is required from the user before taking some destructive action. An application can have any number of broadcast receivers. A broadcast receiver responds by taking a specific action.
• <provider>
tags—Used for declaring content providers. Content providers provide content, that is, data to applications. They help in handling, storing, and sharing data such as audio, images, video, and contact lists with other applications. Android ships with a number of content providers that the applications can use to access and share data with other applications.
• <uses-permission>
tags—Used for declaring the permissions that the application needs.
Example:
<uses-permission android:name="android.permission.CAMERA" />
—Used for the application that needs to use the camera.
<uses-permission android:name="android.permission.INTERNET"/>
—Used for the application that needs to access the Internet
Note
The <uses-permission>
tags are nested within <manifest>
tags. They appear at the same level as the <application>
tag.
To configure the application, you don’t have to manipulate the XML code of the AndroidManifest.xml
file manually; instead you can take the help of the Manifest Editor provided by the Android Development Tools (ADT) plug-in. To use the Manifest Editor in Eclipse, right-click the AndroidManifest.xml
file in the Package Explorer window, and select Open With
, Android Manifest Editor
. This presents the Android Manifest Overview screen, as shown in Figure 2.3.
The screen provides a user-friendly interface to configure the application, enabling you to set the application version information and root-level manifest nodes, including uses-sdk
and uses-permission
, for example. It also provides shortcut links to the Application, Permissions, Instrumentation, and raw XML screens. In short, the task of managing the application—setting icons, setting the theme, applying security, testing settings, and so on—becomes easy through Manifest Editor.
There are three approaches to creating user interfaces in Android. You can create user interfaces entirely in Java code or entirely in XML or in both (defining the user interface in XML and then referring and modifying it through Java code). The third approach, the combined approach, is highly preferred and is the one used in this book. The XML file in which you create the user interface is activity_welcome_msg.xml
found in the res/layout
folder. In the activity_welcome_msg.xml
file, different controls or views that you want to interact with the user are defined. The controls or views in activity_welcome_msg.xml
have to be laid out in some way. The default layout in which the controls or views are usually arranged is RelativeLayout
. The activity_welcome_msg.xml
file is also referred to as the Activity layout file.
Listing 2.3 shows the original content of the layout file activity_welcome_msg.xml
.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/hello_world"
tools:context=".WelcomeMsgActivity" />
</RelativeLayout>
Recall that in this application you want to prompt the user to enter a name, and in return the application displays a welcome message along with the entered name. So, if the name entered is “Kelly,” the application displays “Welcome Kelly!” For the current application, you only need to work with two files: activity_welcome_msg.xml
and the Activity file WelcomeMsgActivity.java
. Let’s begin with the activity_welcome_msg.xml
file. Double-click the activity_welcome_msg.xml
file and overwrite its default content with the code shown in Listing 2.4.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enter your name:"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/user_name"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/click_btn"
android:text="Click Me"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/response"/>
</LinearLayout>
In the preceding XML file, four controls are used: two TextView
s, one EditText,
and one Button
control. The first TextView
prompts the user to enter a name by displaying the message Enter your name: and the second TextView
is used to display the Welcome message to the user. The EditText
control provides a blank text box, allowing the user to enter a name. The Button
control is for generating an event; that is, only when the user selects the Button
control will a welcome message be displayed through the second TextView
control. The EditText
, Button
, and one of the TextView
controls are assigned the IDs user_name, click_btn, and response, respectively. These IDs are used to access these controls in the Java Activity file. The Button
control is assigned the caption Click Me
. The four controls are laid out in LinearLayout
—a placement that arranges the controls contained in it either horizontally or vertically.
The views or the controls that we want to display in an application are arranged in an order or sequence by placing them in the desired layout. The layouts also known as Containers or ViewGroups are used for organizing the views or controls in the required format. Examples of layouts are LinearLayout
, FrameLayout
, and so on. A brief description of layouts follows:
• LinearLayout—In this layout, all elements are arranged in a descending column from top to bottom or left to right. Each element contains properties to specify how much of the screen space it will consume. Depending on the orientation parameter, elements are either arranged in row or column format.
• RelativeLayout—In this layout, each child element is laid out in relation to other child elements. That is, a child element appears in relation to the previous child. Also, the elements are laid out in relation to the parent.
• AbsoluteLayout—In this layout, each child is given a specific location within the bounds of the parent layout object. This layout is not suitable for devices with different screen sizes and hence is deprecated.
• FrameLayout—This is a layout used to display a single view. Views added to this are always placed at the top left of the layout. Any other view that is added to the FrameLayout
overlaps the previous view; that is, each view stacks on top of the previous one.
• TableLayout—In this layout, the screen is assumed to be divided in table rows, and each of the child elements is arranged in a specific row and column.
• GridLayout—In this layout, child views are arranged in a grid format, that is, in the rows and columns pattern. The views can be placed at the specified row and column location. Also, more than one view can be placed at the given row and column position.
Note
The three terms used to represent user interface elements are view, widget, and control. They are used interchangeably in this book.
The following list highlights some of the controls commonly used in Android applications:
• TextView—A read-only text label. It supports multiline display, string formatting, and automatic word wrapping.
• EditText—An editable text box that also accepts multiline entry and word-wrapping.
• ListView—A ViewGroup
that creates and manages a vertical list of views, displaying them as rows within the list.
• Spinner—A TextView
and an associated list of items that allows us to select an item from the list to display in the text box.
• Button—A standard command button.
• CheckBox—A button allowing a user to select (check) or unselect (uncheck).
• RadioButton—A mutually exclusive button, which, when selected, unselects all other buttons in the group.
In our sample application, you want the user to enter a name in the EditText
control. After the user has entered the name and clicks the Button
control, a welcome message displays on the screen. The action of clicking a Button
, pressing the Enter key, or performing any action on any control is considered an event
. The reaction to the event, that is, the action to be taken when the event occurs, is called event handling
. To handle an event, you use the listeners
that wait for an event occurrence. When an event occurs, the listeners
detect it and direct the program to the appropriate routine.
An event listener is an interface in the View
class that contains a single callback method, called an event occurrence. For example the callback method onClick()
is called when the user clicks on a button. For event handling, the event listener is either implemented in the Activity
class or is defined as an anonymous
class. Thereafter, an instance of the implementation is passed to the respective control through the setOnClickListener()
method.
Note
Click is just one type of an event.
In this chapter we discuss three ways of event handling:
• Creating an anonymous inner class
• Implementing the OnClickListener
interface
• Declaring the event handler in the XML definition of the control
In this method of event handling, you implement a listener inline; that is, an anonymous
class is defined with an OnClickListener
interface, and an onClick(View v)
method is implemented in it. The anonymous inner class is passed to the listener through the setOnClickListener()
method. To implement the concept of anonymous inner
class for event handling, the Java activity file WelcomeMsgActivity.java
is modified to appear as shown in Listing 2.5.
package com.androidunleashed.welcomemsg;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.Button;
import android.view.View;
public class WelcomeMsgActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome_msg);
Button b = (Button)this.findViewById(R.id.click_btn);
b.setOnClickListener(new Button.OnClickListener(){
public void onClick(View v) {
TextView resp = (TextView) findViewById(R.id.response);
EditText name = (EditText) findViewById(R.id.user_name);
String str = "Welcome " + name.getText().toString() + " !";
resp.setText(str);
}
});
}
}
You can see that a listener is implemented inline through an anonymous
class with an onClickListener
interface. A callback method onClick(View v)
is implemented in the class, and, finally, the anonymous class is associated with the Button
object b
. Now, whenever the Button
control is clicked in the application, the onClick()
method is invoked. In the onClick()
method, you fetch the TextView
and the EditText
controls defined in the layout file with the IDs response
and user_name
, and then map them to the TextView
and EditText
objects resp
and name
, respectively. That is, the objects resp
and name
represent the TextView
and EditText
controls defined in the layout file. The name entered by the user in the EditText
control is accessed, and, after it is prefixed with a Welcome message, is assigned to a String
object, str
. Finally, the str
object is assigned to the TextView
object, resp
, to display the Welcome message, along with the user’s name on the screen.
Note
The class method onCreate()
is called when the Activity is first created. It is used to initialize the Activity and to create views of the application.
The application is complete. Let’s run it to see its output.
To run the application, you can create an Eclipse launch configuration as described in Chapter 1, “Introduction to Android.” If you run the application without creating a launch configuration, you see the Run As
dialog box shown in Figure 2.4. Choose Android Application
, and a launch configuration is automatically created.
The ADT compiles the application and then deploys it to the emulator with the default launch configuration.
The Android emulator is loaded showing the output of the application. You can see in the emulator that a prompt message Enter your name:
appears via the TextView
control. In addition, a blank text box appears via the EditText
control where you will enter a name, and a button appears via Button
control (see Figure 2.5—top). After you enter the user name Kelly
and select the Click Me
button, a welcome message, Welcome Kelly!
, appears via the TextView
control (see Figure 2.5—bottom). Recall that you defined all these controls in the file activity_welcome_msg.xml
.
You have seen the use of the anonymous inner class in event handling. Next, you try another method of event handling, the Activity Implementing OnClickListener
interface.
In this method of event handling, the Activity class implements the OnClickListener
interface, which requires us to implement the onClick()
method in this class. The onClick()
method is declared inside the class, and the listener is set by passing a reference to the class by the following statement: b.setOnClickListener(this);
To implement the OnClickListener
interface, the activity file WelcomeMsgActivity.java
is modified to appear as shown in Listing 2.6.
package com.androidunleashed.welcomemsg;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.Button;
import android.view.View;
import android.view.View.OnClickListener;
public class WelcomeMsgActivity extends Activity implements OnClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome_msg);
Button b = (Button)this.findViewById(R.id.click_btn);
b.setOnClickListener(this);
}
public void onClick(View v) {
TextView resp = (TextView)this.findViewById(R.id.response);
EditText name = (EditText)this.findViewById(R.id.user_name);
String str = "Welcome " + name.getText().toString() + " !";
resp.setText(str);
}
}
This code locates the Button
control that you created in the activity_welcome_msg.xml
file (with the ID click_btn
), assigns it to the instance b
, and attaches an event listener to it. When the event occurs via a button click, the onClick()
method is executed. The TextView
and EditText
controls of activity_welcome_msg.xml
are located and accessed via the resp
and name
objects, respectively. The username entered in the EditText
control is fetched and displayed along with a welcome message via the TextView
control; that is, we get the same output as shown previously in Figure 2.5.
In the WelcomeMsg
application, an event such as Click
occurs via the Button
control, which, in turn invokes the respective event handler that does the desired action.
Besides the Java code, you can define the event handler in the XML file too. That is, you can declare the event handler in the XML definition of the control and define the event handler in the Activity class. Let’s discuss this process in detail.
Since Android SDK 1.6, there has been another way to set up a click handler for the Button
controls. In the XML definition of a Button
in the layout file activity_welcome_msg.xml
, you can add an android:onClick
attribute. This attribute is used to represent the method you want to execute when a click event occurs via the Button
control. For example, the following statement declares the dispMessage()
method as the event handler for the button when a click event occurs:
android:onClick="dispMessage"
All you need to do is define the dispMessage()
in the Activity class to perform the desired action.
Remember, to try out this method of event handling, you need to modify the layout file activity_welcome_msg.xml
of the application. The code that we write in the activity_welcome_msg.xml
file is as shown in Listing 2.7. The statement in bold is the newly added code; the rest is the same as Listing 2.4.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enter your name:"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/user_name"/>
<Button
android:id="@+id/click_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Me"
android:onClick="dispMessage" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/response"/>
</LinearLayout>
In this code block, the attribute android:onClick
means that the dispMessage()
method must be invoked when the button is clicked. Note that you can declare the same event handler for several controls; that is, you can declare the dispMessage()
method as the event handler for multiple buttons.
In the Java Activity file WelcomeMsgActivity.java
, the method dispMessage()
is defined. This method performs the task of accessing the name entered in the EditText
control and displaying a welcome message along with the entered name. After you add the method dispMessage()
, the Activity file WelcomeMsgActivity.java
appears as shown in Listing 2.8.
package com.androidunleashed.welcomemsg;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.EditText;
public class WelcomeMsgActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome_msg);
}
public void dispMessage(View v) {
TextView resp = (TextView) findViewById(R.id.response);
EditText name = (EditText) findViewById(R.id.user_name);
String str = "Welcome " + name.getText().toString() + " !";
resp.setText(str);
}
}
You can see in the dispMessage()
method that the TextView
and EditText
controls with the IDs response and user_name are accessed from the layout file, activity_welcome_msg.xml
and mapped to the TextView
and EditText
objects resp and name, respectively. The username entered in the EditText
control is accessed through the name object (EditText
control) and is assigned to the resp object (TextView
control) along with the welcome message for display. On running the application, you get the same output shown previously in Figure 2.5 (top and bottom).
Can you define the same event handler method in more than one Button
control? The answer is yes. But you might think that if the same event handler, dispMessage
, is declared in more than one Button
control, then how does the application know which control has invoked it? The solution is the View
object; that is, the control on which the event has occurred is also passed to the event handler. In the event handler, the getId()
method of the View
object can be used to discover the button from which the event has occurred and an appropriate action can be taken, as shown in the following code snippet:
public void dispMessage(View v) {
if (v.getId()==R.id.id1) {
}
if (v.getId()==R.id.id2) {
}
......
.....
}
id1 and id2
are the IDs of the button controls that declare the same event handler.
Previously in Listing 2.7, notice that we used two TextView
controls. The first TextView
control is used for displaying the text Enter your name. The second TextView
does the task of displaying a welcome message to the user.
Is there any other way of displaying a response in an Android application besides using the TextView
control? Yes, you can use Toast
class for displaying output.
A Toast
is a transient message that automatically disappears after a while without user interaction. It is usually used to inform the user about happenings that are not very important and does not create a problem if they go unnoticed. A Toast
is created by calling the static method, makeText()
, of the Toast
class. The syntax of the makeText()
method is shown here:
Toast.makeText(activity_context, string_to_display, duration)
The method needs the Activity
(Context
) String
to display, as well as the duration
for which the message is displayed on the screen. You can also supply the ID of the String resource that you want to display. The duration is expressed in the form of constants, such as Toast.LENGTH_SHORT
or Toast.LENGTH_LONG
, to determine the duration for which the string’s message remains on the screen. The method returns a Toast
instance. You call the show()
method on the returned Toast
instance to display the containing string or message. You learn about string resources in Chapter 4.
To display the welcome message through Toast
, modify the Java activity file WelcomeMsgActivity.java
as shown in Listing 2.9. Only the code in bold is new.
package com.androidunleashed.welcomemsg;
import android.app.Activity;
import android.os.Bundle;
import android.widget.EditText;
import android.view.View;
import android.widget.Toast;
public class WelcomeMsgActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome_msg);
}
public void dispMessage(View v) {
EditText name = (EditText) findViewById(R.id.user_name);
String str = "Welcome " + name.getText().toString() + " !";
Toast.makeText(WelcomeMsgActivity.this, str, Toast.LENGTH_SHORT).show();
}
}
You can see that a String
object, str
, is defined, which contains a Welcome
message and the name entered by the user in the EditText
control with the ID user_name
. The text in the String
object, str
, is displayed via Toast
, as shown in Figure 2.6. The message Welcome Kelly !
automatically disappears after a while.
Since a Toast
is transient, it is not visible for an extensive period, and you don’t receive any confirmation that the user actually saw it. Therefore, we continue to use the TextView
control in Android applications to display information to the user.
In Listing 2.9, you saw that the Activity of the application is automatically created by the ADT that drives the application. Can we create our own activity? Let’s see how in the next section.
The structure that is used to start, stop, and transition between Activities within an application is called an Intent
.
An intent is a data structure that describes operations to perform in an Android application. It consists of an action that the application needs to perform, data to operate on, and other information helpful in executing the operation. Intent can be explicit or implicit as follows:
• Explicit Intent—In an explicit intent, you specify the Activity required to respond to the intent; that is, you explicitly designate the target component. Because the developers of other applications have no idea of the component names in your application, an explicit intent is limited to be used within an application—for example, transferring internal messages.
• Implicit Intent—In an implicit intent, you just declare intent and leave it to the platform to find an Activity that can respond to the intent. That is, you don’t specify the target component that should respond to the intent. This type of intent is used for activating components of other applications. It is the job of the Android platform to search for the most suitable component to handle the implicit intent.
The method used to start an activity is startActivity()
. First create an implicit or explicit intent object and pass it to the startActivity()
method in the format shown here:
startActivity(my_intent);
where my_intent
refers to the intent that is passed to the method as a parameter. The startActivity()
method finds and starts the single Activity that best matches the given intent.
To explicitly specify the Activity that you want to start through an intent, create a new intent specifying the current application context and the class name of the activity you want to launch and pass this Intent
to the startActivity()
method, as shown here:
startActivity(new Intent(this, Welcome.class));
In the preceding statement, you created an explicit intent and initialized it by passing the Activity context, this and the Welcome
’s class instance, which is the activity that you want to launch. The Intent
object is passed to the startActivity()
method, which launches the activity described by Welcome.class
. If startActivity()
is unable to find the specified activity, an android.content.ActivityNotFoundException
is thrown.
Let’s explore the concept of creating and starting your own activity using an example. You create an application similar to the WelcomeMsg
application but with the following two differences:
• Instead of using the default Activity automatically created by the ADT, you create your own Activity in this application.
• You create and use your own layout file instead of the default layout file.
Launch Eclipse and create a new Android Project called WelcomeApp
with the following settings:
• Select Android 4.1
as the Target
platform.
• Let the application name be the default, which is WelcomeApp
.
• Let the package name be com.androidunleashed.welcomeapp
.
• Let the Activity name be the default, which is WelcomeAppActivity
.
From now on, we call the settings shown here the default settings. Almost all applications in this book will be created with these default settings unless otherwise specified.
In any new Android project that you create, ADT creates a layout file activity_welcome_app.xml
by default. But as mentioned earlier, in this application you learn to create and use your own layout file.
To create a new layout file, from the Package Explorer
window, right click the res/layout
folder and select the New
, Android XML File
option. A dialog box appears asking for information about the new Android XML File. In the File
text box, enter the filename as welcome
(no need to add the .xml
extension). Select the option LinearLayout
from the Root Element
, which denotes that you want to create a linear layout file, and finally, select the Finish
button. The layout file, welcome.xml
, is created in the res/layout
folder. The initial content of the file is shown in Listing 2.10.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
Let’s add two TextView
controls, an EditText
and a Button
control, to the layout file (the same controls as in the WelcomeMsg
application). After you add these controls, the contents of the welcome.xml
file will be as shown in Listing 2.11.
<?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">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Enter your name:"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/user_name"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/click_btn"
android:text="Click Me"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/response"/>
</LinearLayout>
After the layout file is completed, it’s time to create a new Activity.
You know that an Activity file is in the form of a Java file. So, you need to add a Java file to the package com.androidunleashed.welcomeapp
that’s inside the src
folder of the application. Click the src
node in the Package Explorer
window to expand it. The package com.androidprogrs.welcomeapp
is displayed, showing the default Activity file WelcomeAppActivity.java
inside it. To create an Activity, right-click the package com.androidunleashed.welcomeapp
and select the New
, Class
option. A New Java Class
dialog box appears, requesting you to enter the name of the Java file. In the Name
text box, enter the name of the Activity file, Welcome
(no need to add the .java
extension). Keeping all the default options selected, select the Finish
button to create the Java file.
The Activity Welcome.java
is added to the package with the default content, as shown here:
package com.androidunleashed.welcomeapp;
public class Welcome {
}
Let’s add some action to the Activity file. Recall that this application is similar to the WelcomeMsg
application that you created before; that is, it prompts the user to enter a name and prints a welcome message when the Button
control is selected. So, let’s add the code shown in Listing 2.12 to the newly created Activity file.
package com.androidunleashed.welcomeapp;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.Button;
import android.view.View;
public class Welcome extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome);
Button b = (Button)this.findViewById(R.id.click_btn);
b.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
TextView resp = (TextView) findViewById(R.id.response);
EditText name = (EditText) findViewById(R.id.user_name);
String str = "Welcome " + name.getText().toString() + " !";
resp.setText(str);
}
});
}
}
Only the components declared in the application’s manifest file AndroidManifest.xml
are visible to Android and hence can be used to run the application. This means that the new Activity Welcome.java
must be declared in the AndroidManifest.xml
file to make it visible to Android and start it. The AndroidManifest.xml
file is shown in Listing 2.13. The statement in bold is added to register the newly created activity, Welcome.java
.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidunleashed.welcomeapp"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".WelcomeAppActivity"
android:label="@string/title_activity_welcome_app" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Welcome" android:label="@string/app_name" />
</application>
</manifest>
After registering the Activity Welcome.java
in the AndroidManifest.xml
file, you can now start it by using the startActivity()
method discussed at the beginning of the section. Because the new Activity is started from the default activity file of the application WelcomeAppActivity.java
, the startActivity()
method needs to be added to the same file. The code in the default Activity file WelcomeAppActivity.java
, after adding the startActivity()
method, appears as shown in Listing 2.14.
package com.androidunleashed.welcomeapp;
import android.app.Activity;
import android.os.Bundle;
import android.content.Intent;
public class WelcomeAppActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome_app);
startActivity(new Intent(this, Welcome.class));
}
}
The statements in bold are the statements just added to the file; the remainder is the default code provided by ADT. The startActivity()
method creates an explicit intent, which explicitly specifies that the Activity file Welcome.java
is to be run at the start. When the application is run, you see the same output as that of the WelcomeMsg
application (see Figure 2.5, left and right).
Before we move on to the next application, let’s have a quick look at the attributes that can be used in XML definitions of the EditText
and Button
controls to configure them.
The EditText
control is a subclass of TextView
and is used for getting input from the user. You can use several attributes to configure the EditText
control to suit your requirements. For example, you can implement the scrolling feature to scroll the text when the user types beyond the width of the control or the auto text feature to correct common spelling mistakes while the user types. The default behavior of the EditText
control is to display text as a single line and run over to the next line when the user types beyond the width of the control. By applying attributes, you can constrain the EditText
control to remain on a single line only and let the text scroll to the left. You can also hide the characters typed by the user for security purposes, that is, convert the characters into dots, which you usually see while typing passwords.
Example:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter your name"
android:singleLine="false"
android:id="@+id/user_name" />
The preceding example sets the EditText
control to expand to multiple lines when the user types beyond the width of the control. Also, the control displays the hint text Enter your name
, which is automatically erased as the user types data.
The list of attributes that can be used to configure EditText
control are discussed in the following section.
The following is a list of attributes that can be used to configure the EditText
control:
• android:layout_width—Used to set the width of the EditText
control. The two valid values are wrap_content
and match_parent
. The value wrap_content
sets the width of the EditText
control to accept only a single character. When the user types text, the width of the EditText
control automatically increases to accommodate the new content. Also, the cursor moves to the next line when the boundary of the container is reached. No text scrolling takes place unless the android:scrollHorizontally
attribute is set to "true"
. In this case, instead of moving to the next line, the text scrolls left to accommodate the newly typed content. If the value of the android:layout_width
attribute is set to match_parent
, the width of the EditText
control is set equal to the width of its container. When the user types the text beyond the available width, the cursor moves to the next line.
• android:layout_height—Used to set the height of the EditText
control. Valid values are wrap_content
and match_parent
. When the value wrap_content
is assigned to the control, the height of the EditText
control increases when typing text beyond the width of the control. If the value match_parent
is assigned to the control, text expands the height of the control to fill up the height of the container.
• android:singleLine—When set to true
, forces the EditText
control to remain on a single line. That is, on reaching the end of the available width, the text that is typed in scrolls to the left. If the value is set to false
, the cursor moves to the next line when the end of the available width of the control is reached.
• android:hint—Displays helpful text in the EditText
control to guide user entry. The text automatically disappears when the user enters data. For example, android:hint="Enter your name"
displays the text Enter your name
in the EditText
control to indicate that a name has to be entered in this EditText
control.
• android:lines—Sets the height of the EditText
control to accommodate the specified number of lines. For example, android:lines="5"
sets the height of EditText
control to accommodate five lines. Typing text beyond the fifth line causes the text to scroll up to accommodate input.
• android:textSize—Sets the size of the text typed in the EditText
control. You can specify the size in any of the following units of measurement: px
, in
, mm
, pts
, dip
, and sp
. For example, android:textSize="15px"
sets the size of text typed in the EditText
control to 15 pixels. The recommended unit for text size is sp
as it works correctly across different screen sizes and densities.
• android:autoText—When set to true
enables the EditText
control to correct common spelling mistakes.
• android:capitalize—Automatically converts typed text into capital letters. The valid values are none
, characters
, words
, and sentences
. The value none
does not capitalize anything. The value characters
capitalizes every character. The value words
capitalizes the first character of every word. The value sentences
capitalizes the first character of the first word of each sentence.
• android:password—When set to true
, the attribute converts the typed characters into dots to hide entered text.
• android:minWidth—Used to specify the minimum width of the control.
• android:maxWidth—Used to specify the maximum width of the control. Text typed beyond the maximum width scrolls if the android:scrollHorizontally
attribute is set to true
; otherwise, it moves onto the next line.
• android:minHeight—Used to specify the minimum height of the control.
• android:maxHeight—Used to specify the maximum height of the control.
• android:scrollHorizontally—When set to true
, makes the text scroll horizontally if typed beyond the specified width of the control.
• android:inputType—Specifies the type of data that will be typed in the EditText
control. This attribute configures the onscreen keyboard too. There are many possible values that include number
, phone
, text
, textCapCharacters
, textCapWords
, textEmailAddress
, datetime
, date
, time
, textAutoCorrect
, textMultiLine
, and textPassword
. Figure 2.7 (first through fifth image) shows how the onscreen keyboard changes when the values number
, phone
, text
, textCap Characters
, and textEmailAddress
are assigned to this attribute, respectively. This single attribute actually replaces many attributes such as android:password
, android:singleLine
, android:numeric
, android:phoneNumber
, android:capitalize
, and android:autoText.
In the WelcomeMsg
application that you created earlier, you saw that an event listener was associated with the Button
control; that is, the application performs an action when the user performs an event (clicks) on the Button
control. Is it essential to have a Button
control to initiate action? Can’t you initiate an action by pressing the Enter key on the EditText
control? In other words, can you add an event listener to the EditText
control? The answer is yes! Let’s see how.
In this section, you learn how to add an event listener to the EditText
control that checks for the occurrence of an event in the EditText
control and executes the callback method accordingly. You use a practical approach by creating a new Android application to perform this action. In this application, an EditText
control is displayed on the screen asking the user to enter a name. After the user enters a name and presses the Enter key, a welcome message displays via the TextView
control.
First launch Eclipse and create a new Android project called EditTextApp
, and modify activity_edit_text_app.xml
as shown in Listing 2.15.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter your name"
android:id="@+id/user_name"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/response"/>
</LinearLayout>
You can see that the layout contains two controls: EditText
for getting the name from the user and TextView
for displaying a welcome message. The EditText
and TextView
controls are assigned the user_name
and response
IDs, respectively. The EditText
control displays hint text, Enter your name
, to indicate that a name must be entered in the EditText
control.
To add an action, that is, to display the welcome message when the user presses the Enter key after entering a name, we need to write code in the Activity file. Let’s put the code shown in Listing 2.16 into the Activity file EditTextAppActivity.java
.
package com.androidunleashed.edittextapp;
import android.app.Activity;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.TextView;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.KeyEvent;
public class EditTextAppActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_text_app);
final TextView resp = (TextView)this.findViewById(R.id.response);
final EditText username = (EditText) findViewById(R.id.user_name);
username.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((event.getAction() == KeyEvent.ACTION_UP) && (keyCode ==
KeyEvent.KEYCODE_ENTER)) {
resp.setText("Welcome "+username.getText()+" !");
return true;
}
return false;
}
});
}
}
In Listing 2.16, the EditText
control from the layout is captured and mapped to the username EditText
object. To display the welcome message to the user, the TextView
control with the response
ID is captured from the layout and assigned to the TextView
object resp
. An event listener, OnKeyListener
, is added to the EditText
object username so that the callback method onKey()
is invoked whenever a key is pressed. The onKey()
method is implemented, and it checks whether the Enter key is pressed. When the Enter key is pressed, a welcome message is displayed to the user through the TextView
object, resp
. The onKey()
method is set to return false
until the Enter key is pressed. The onKey()
method is set to return true
when the Enter key is pressed by the user.
Note
The onKey()
method is set to return true
if the event is handled and you want no other handler to listen to the events. You set this method to return false
if the event is not handled and you want the method to listen for more key presses and to continue handling events.
You see the output shown in Figure 2.8 (top). You can see the hint text Enter your name
in the EditText
control. After the user has entered a name and pressed the Enter key, the username and the welcome message appear, as shown in Figure 2.8 (bottom).
While developing applications, you may encounter a situation where you want to display certain options for the user to select. The two controls that enable you to do this are CheckBox
and RadioButton
.
A checkbox
control has two states: checked
and unchecked.
When the check box is selected, it toggles its state from checked to unchecked and vice versa. A check box is created via an instance of android.widget.CheckBox
.
In Java, the following methods can be used with Checkbox
controls:
• isChecked()—Determines whether the check box is checked
• setChecked()—Sets or changes the state of the check box
• toggle()—Toggles the state of the check box from checked to unchecked or vice versa
To add an event listener, you can implement the OnCheckedChangeListener
interface that invokes the callback method onCheckedChanged()
when the state of the check box changes. In addition, you can also use the traditional implementation, the OnClickListener
interface, that invokes the onClick()
method when any of the CheckBox
controls are clicked.
Example:
<CheckBox
android:id="@+id/purchase"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="Purchase" />
The preceding example shows a Purchase check box that the user can select to indicate that he or she wants to purchase an item.
To learn the concept of CheckBox
, let’s create an Android application based on these controls. In this application, you create three CheckBox
controls, each representing a food item along with its price (see Figure 2.9—left). When the food items are selected, the total price is displayed. The application shows us how CheckBox
controls are displayed, how event listeners are attached to them, and whether the CheckBox
is in a checked or unchecked state. Let’s start with the application.
Launch Eclipse, create a new Android project called CheckBoxApp
, and add three CheckBox
controls to the Activity layout file activity_check_box_app.xml
, as shown in Listing 2.17.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Select Items you want"/>
<CheckBox
android:id="@+id/checkbox_pizza"
android:layout_height="wrap_content"
android:text="Pizza $15"
android:layout_width="match_parent" />
<CheckBox
android:id="@+id/checkbox_hotdog"
android:layout_height="wrap_content"
android:text="Hot Dog $5"
android:layout_width="match_parent" />
<CheckBox
android:id="@+id/checkbox_burger"
android:layout_height="wrap_content"
android:text="Burger $10"
android:layout_width="match_parent" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/bill_btn"
android:text="Calculate Bill"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/amount"/>
</LinearLayout>
You can see that two TextViews
, three CheckBoxes
, and a Button
control are defined in Listing 2.17. The first TextView
is for displaying a message, Select Items you want
, asking the user to select the food items using the CheckBox
controls. The three CheckBox
es are assigned unique IDs—checkbox_pizza
, checkbox_hotdog
, and checkbox_burger
—and they represent the food items, Pizza
, HotDog
, and Burger
, respectively. The caption and ID assigned to the Button
control are bill_btn
and Calculate Bill
, respectively. The second TextView
is assigned the ID amount
and is meant for displaying the total price of the food items selected by the user.
To add an action to the application, that is, to check the status of each of the CheckBox
controls and to print the sum of the food items selected, you need to write some Java code in the Activity file. Let’s write the code shown in Listing 2.18 in the Activity file CheckBoxAppActivity.java
.
package com.androidunleashed.checkboxapp;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.CheckBox;
import android.view.View;
import android.view.View.OnClickListener;
public class CheckBoxAppActivity extends Activity implements OnClickListener {
CheckBox c1,c2,c3;
TextView resp;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_check_box_app);
Button b = (Button)this.findViewById(R.id.bill_btn);
resp = (TextView)this.findViewById(R.id.amount);
c1 = (CheckBox)findViewById(R.id.checkbox_pizza);
c2 = (CheckBox)findViewById(R.id.checkbox_hotdog);
c3 = (CheckBox)findViewById(R.id.checkbox_burger);
b.setOnClickListener(this);
}
public void onClick(View v) {
int amt=0;
if (c1.isChecked()) {
amt=amt+15;
}
if (c2.isChecked()) {
amt=amt+5;
}
if (c3.isChecked()) {
amt=amt+10;
}
resp.setText("Bill is " +Integer.toString(amt));
}
}
The Button
control with the ID bill_btn
is accessed from the layout file and is mapped to the Button
object b
. The TextView
control with the ID amount
is accessed from the layout file and is mapped to the TextView
object resp
. Similarly, the three CheckBox
es with the IDs checkbox_pizza
, checkbox_hotdog
, and checkbox_burger
are accessed from the layout file and mapped to the CheckBox
objects c1
, c2
, and c3
, respectively. An event handler, setOnClickListener
, is attached to the button. Hence, whenever the button is clicked, the onClick()
method is called. In the onClick()
method, an integer variable amt
is initialized to 0. The state of each check box is checked through the isChecked()
method. The isChecked()
method returns the Boolean value true
if the check box is checked; otherwise, it returns false
. The three check boxes represent the food items Pizza, HotDog, and Burger, respectively. The state of each check box is checked, and if any of them is selected, the amount associated with that food item is added to the amt
variable. That is, the total amount of the selected food item is computed and stored in the amt
variable. The total in the amt
variable is displayed on the screen by assigning it to the TextView
object resp
. When the application is run, you get the screen shown in Figure 2.9 (left). No total is displayed, as no food item has been selected. When a check box is selected, the total price of the selected food items is displayed, as shown in Figure 2.9 (middle and right).
What if you want users to select only a single option from a group? The solution is using the RadioButton
control.
RadioButton
controls are two-state widgets that can be in either a checked or unchecked state. The difference between check boxes and radio buttons is that you can select more than one check box in a set, whereas radio buttons are mutually exclusive—only one radio button can be selected in a group. Selecting a radio button automatically deselects other radio buttons in the group.
To make them mutually exclusive, RadioButton
controls are grouped together into the RadioGroup
element so that no more than one can be selected at a time. To create a group of radio buttons, first create a RadioGroup
and then populate the group with few RadioButton
controls, as shown in the following example:
<RadioGroup
android:id="@+id/group_hotel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RadioButton android:id="@+id/radio_fivestar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Five Star " />
<RadioButton android:id="@+id/radio_threestar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Three Star" />
</RadioGroup>
In the preceding code block, a RadioGroup
with the group_hotel
ID is defined, which contains two RadioButton
controls with the IDs radio_fivestar
and radio_threestar
, respectively. Because only a single radio button in a group can be in a checked state, checking a radio button automatically unchecks the other radio button in the group.
In Java, the following methods can be applied to RadioButton
s:
• isChecked()—Detects whether the RadioButton
control is selected.
• toggle()—Toggles the state of the RadioButton
from selected to unselected and vice versa.
• check()—Checks a specific RadioButton
whose ID is supplied in the method.
• getCheckedRadioButtonId()—Gets the ID of the currently selected RadioButton
control. It returns –1 if no RadioButton
control is checked.
Let’s create an application using the concept of radio buttons. In this application, you define two RadioButton
controls in a RadioGroup
. Each RadioButton
represents a hotel type, and whenever a RadioButton
is selected, the hotel type represented by it will be displayed through a TextView
control (see Figure 2.9—middle). It is obvious that when a RadioButton
representing a hotel type is selected, any other previously selected RadioButton
is automatically unselected. The application shows how RadioButton
controls are defined, how they are nested in RadioGroup
controls, and how an event listener is attached to them. Let’s start with the application.
Launch Eclipse, create a new Android project called RadioButtonApp
, and add two RadioButton
controls to the Activity layout file activity_radio_button_app.xml
, as shown in Listing 2.19.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Select the type of hotel"/>
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/radio_fivestar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Five Star " />
<RadioButton android:id="@+id/radio_threestar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Three Star" />
</RadioGroup>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/hoteltype"/>
</LinearLayout>
In Listing 2.19, you can see that two RadioButton
controls with the radio_fivestar
and radio_threestar
IDs are grouped inside a RadioGroup
. This means that the two radio buttons have become mutually exclusive—selecting one radio button automatically deselects the other radio button.
To add an event listener action to the two RadioButton
controls, you need to write some Java code in the Activity file. Let’s write the code shown in Listing 2.20 in the Activity file RadioButtonAppActivity.java
.
package com.androidunleashed.radiobuttonapp;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.RadioButton;
import android.view.View;
import android.view.View.OnClickListener;
public class RadioButtonAppActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_radio_button_app);
RadioButton radioFivestar = (RadioButton) findViewById(R.id.radio_fivestar);
RadioButton radioThreestar = (RadioButton) findViewById(R.id.radio_threestar);
radioFivestar.setOnClickListener(radioListener);
radioThreestar.setOnClickListener(radioListener);
}
private OnClickListener radioListener = new OnClickListener() {
public void onClick(View v) {
TextView selectedHotel = (TextView) findViewById(R.id.hoteltype);
RadioButton rb = (RadioButton) v;
selectedHotel.setText("The hotel type selected is: " +rb.getText());
}
};
}
The two RadioButton
controls are captured from the layout and mapped to the RadioButton
objects radioFivestar
and radioThreestar
. The View.OnClickListener
interface is implemented to listen to the click events on the RadioButton
controls. The onClick()
callback method is implemented. This is the method that is executed when any of the RadioButton
controls are selected. In the onClick()
callback method, the TextView
control from the layout is captured and mapped to the TextView
object selectedHotel.
Also, the text content of the RadioButton
control that is selected by the user is fetched through the getText()
method and is displayed through the TextView
object selectedHotel.
On execution of the application, you see two RadioButton
controls on the startup screen, as shown in Figure 2.10 (left). When the user selects the five star RadioButton
, the TextView
displays the message The hotel type selected is: Five Star
(see Figure 2.10—middle). Similarly, when the user selects the three star RadioButton
, the TextView
displays the message The hotel type selected is: Three Star
(see Figure 2.10—right).
In the preceding application you have a single set of RadioButton
controls nested inside a RadioGroup
. What if you want to display two sets of RadioButton
controls, asking the user to select a RadioButton
from both sets? For example, the user needs to select the type of the hotel, as well as the type of room. In that case, you need to create two RadioGroup
controls: one to represent hotel types and the other to represent room types. The RadioGroup
that represents hotel types will have two RadioButton
controls showing the text Five Star and Three Star. Similarly, the other RadioGroup
that represents room types will have three RadioButton
controls to show three options: Ordinary Room, Luxury Room, and Grand Suite. The layout file with two RadioGroup
controls appears as shown in Listing 2.21.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Select the type of hotel"/>
<RadioGroup android:id="@+id/group_hotel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/radio_fivestar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Five Star " />
<RadioButton android:id="@+id/radio_threestar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Three Star" />
</RadioGroup>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Select the type of room"/>
<RadioGroup android:id="@+id/group_room"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/radio_suite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Grand Suite " />
<RadioButton android:id="@+id/radio_luxury"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Luxury Room" />
<RadioButton android:id="@+id/radio_ordinary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ordinary Room" />
</RadioGroup>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/hoteltype" />
</LinearLayout>
To make two independent sets of radio buttons, one to represent hotel types and another to represent room types, you create two RadioGroup
controls with the group_hotel
and group_room
IDs. The first RadioGroup
, group_hotel
, contains two RadioButton
controls with the radio_fivestar
and radio_threestar
IDs to represent five star and three star hotels. Similarly, the next RadioGroup
, group_room
, contains three RadioButton
controls with the radio_suite
, radio_luxury
, and radio_ordinary
IDs to represent the suite, luxury, and ordinary room types. The two TextView
controls are used to display the messages Select the type of hotel
and Select the type of room
, asking the user to select the type of hotel and room. The third TextView
with the hoteltype
ID is used to display the options selected by the user. To make the two RadioGroup
s functional and to display the hotel and room type selected by the user, write the code shown in Listing 2.22 in the Java activity file RadioButtonAppActivity.java
.
package com.androidunleashed.radiobuttonapp;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.RadioButton;
import android.view.View;
import android.view.View.OnClickListener;
public class RadioButtonAppActivity extends Activity {
String str1="";
String str2="";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_radio_button_app);
RadioButton radioFivestar = (RadioButton) findViewById(R.id.radio_fivestar);
RadioButton radioThreestar = (RadioButton) findViewById(R.id.radio_threestar);
RadioButton radioSuite = (RadioButton) findViewById(R.id.radio_suite);
RadioButton radioLuxury = (RadioButton) findViewById(R.id.radio_luxury);
RadioButton radioOrdinary = (RadioButton) findViewById(R.id.radio_ordinary);
radioFivestar.setOnClickListener(radioListener1);
radioThreestar.setOnClickListener(radioListener1);
radioSuite.setOnClickListener(radioListener2);
radioLuxury.setOnClickListener(radioListener2);
radioOrdinary.setOnClickListener(radioListener2);
}
private OnClickListener radioListener1 = new OnClickListener() {
public void onClick(View v) {
TextView selectedOptions = (TextView) findViewById(R.id.hoteltype);
RadioButton rb = (RadioButton) v;
str1="The hotel type selected is: " +rb.getText();
selectedOptions.setText(str1+"
"+str2);
}
};
private OnClickListener radioListener2 = new OnClickListener() {
public void onClick(View v) {
TextView selectedOptions = (TextView) findViewById(R.id.hoteltype);
RadioButton rb = (RadioButton) v;
str2="Room type selected is: " +rb.getText();
selectedOptions.setText(str1+"
"+str2);
}
};
}
The RadioButton
controls with IDs radio_fivestar
, radio_threestar
, radio_suite
, radio_luxury
, and radio_ordinary
are captured from the layout file and mapped to the RadioButton
objects radioFivestar
, radioThreestar
, radioSuite
, radioLuxury
, and radioOrdinary
, respectively. Two event listener interfaces are created, radioListener1
and radioListener2
. One checks for event occurrences in the RadioButton
controls in group_hotel
, and the other checks for the occurrence of events in the RadioButton
controls in group_room
. Both the interfaces have the callback method onClick()
implemented in them.
When any of the RadioButton
controls in the first RadioGroup
, group_hotel
, is selected, the callback method onClick()
of radioListener1
is executed and text is assigned to the string str1
to represent the RadioButton
selected in that radio group. Similarly, when any RadioButton
control from the second RadioGroup
, group_room
, is selected, the callback method onClick()
of radioListener2
is executed. This assigns text to the string str2
to represent the RadioButton
selected in that radio group. The TextView
with the hoteltype
ID is captured from the layout file and is mapped to the TextView
object selected Options
. The text messages in both the str1
and str2
strings are assigned to the TextView
control selectedOptions
for display. On running the application, you see two sets of RadioButton
controls in their respective RadioGroups
(see Figure 2.11—left). When the five star RadioButton
from the RadioGroup group_hotel
and the RadioButton
luxury room from the RadioGroup group_room
are selected, the TextView
displays the message The hotel type selected is: Five Star Room; Type selected is: Luxury Room
(see Figure 2.11—middle). Similarly, when the three star RadioButton
control from the RadioGroup group_hotel
and the grand suite RadioButton
from the RadioGroup group_room
are selected, the TextView
displays the message The hotel type selected is: Three Star and Room type selected is: Grand Suite
(see Figure 2.11—right).
The main focus of this chapter was to understand the working of basic widgets such as EditText
, CheckBox
, and RadioButton
, and to develop Android applications using these controls. You also learned the role of the folders and files automatically created by the ADT plug-in. You learned about Activities, the Android Activity life cycle, the usage of the Android Manifest file, commonly used layouts and controls, and how events are handled in Android applications. To respond to different events, you learned to create anonymous inner
classes, implement the OnClickListener
interface, and declare the event handler in the XML definition of the control. You also saw how to describe operations through Intent
, create your own layout file, create a new Activity, register the new Activity, and finally, the steps needed to start the Activity.
In the next chapter, you learn about containers—the different types of layouts used to organize and arrange the controls of an application. You learn to use LinearLayout
, RelativeLayout
, AbsoluteLayout
, FrameLayout
, and TableLayout
. Also you learn to adapt to the screen orientation. In addition, you learn the usage of different attributes that help in laying out controls in different layouts. You learn to apply different attributes in the layouts such as the Orientation
attribute, Height
and Width
attributes, Padding
attribute, Weight
attribute, and Gravity
attribute.
18.219.102.189