Chapter 2. Basic Widgets

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.

Understanding the Role of Android Application Components

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).

Image

Figure 2.1. Specifying the project name (left), and specifying the application target (right)

• 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.

Understanding the Utility of Android API

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.

Table 2.1. The Android Platform and Corresponding API Levels

Image

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).

Image

Figure 2.2. Package Explorer window showing different directories, subdirectories, and files automatically created by ADT

Let’s take a quick look at the different folders and files created by ADT.

Overview of the Android Project Files

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.

Listing 2.1. Default Code in the WelcomeMsgActivity.java File


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;
    }
}


Understanding Activities

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.

Understanding the Android Activity Life Cycle

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.

Table 2.2. List of Methods Instantiated During Different Events of an Android Activity Life Cycle

Image

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.

Role of the Android Manifest File

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.

Listing 2.2. Default Code in the Android Manifest File


<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.


Using the Manifest Editor

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.

Image

Figure 2.3. Manifest Editor

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.

Creating the User Interface

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.

Listing 2.3. Default Code in the activity_welcome_msg.xml File


<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.

Listing 2.4. Code Written in the activity_welcome_msg.xml File


<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 TextViews, 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.

Commonly Used Layouts and Controls

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.

Event Handling

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

Creating an Anonymous Inner Class

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.

Listing 2.5. Code Written in the WelcomeMsgActivity.java File


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.

Running the Application

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.

Image

Figure 2.4. Run As dialog box asking the way to run the current application

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.

Image

Figure 2.5. (top) Application asking for the username, and (bottom) Welcome message displayed along with the username

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.

Activity Implementing the 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.

Listing 2.6. Implementing the OnClickListener Interface in the WelcomeMsgActivity.java File


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.

Declaring the Event Handler in the XML Control Definition

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.

Listing 2.7. Declaring an Event Handler in the activity_welcome_msg.xml File


<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.

Listing 2.8. Adding the dispMessage() Method to the WelcomeMsgActivity.java File


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.

Displaying Messages Through Toast

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.

Listing 2.9. WelcomeMsgActivity.java File for Displaying a Message Through Toast


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.

Image

Figure 2.6. Displaying a Welcome message through Toast

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.

Creating and Starting an Activity

The structure that is used to start, stop, and transition between Activities within an application is called an Intent.

Describing Operations Through 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.

Method Used to Start an Activity

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.

Creating 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.

Listing 2.10. Default Code in the welcome.xml File


<?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.

Listing 2.11. Code Written in the welcome.xml File


<?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.

Creating 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.

Listing 2.12. Code Written in the Welcome.java 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);
            }
        });
    }
}


Registering the New Activity

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.

Listing 2.13. The AndroidManifest.xml File


<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>


Starting the Activity

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.

Listing 2.14. The WelcomeAppActivity.java File


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.

Using the EditText Control

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.

Attributes Used to Configure the EditText Control

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.

Image

Figure 2.7. (first) Keyboard when inputType is number, (second) keyboard when inputType is phone, (third) keyboard when inputType is text, (fourth) keyboard when inputType is textCapCharacters, and (fifth) keyboard when inputType is textEmailAddress

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.

Adding an Event Listener to the EditText Control

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.

Listing 2.15. The activity_edit_text_app.xml File


<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.

Listing 2.16. The EditTextAppActivity.java File


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).

Image

Figure 2.8. EditTextApp displaying the hint text Enter your name (top), and welcome message displayed when the Enter key is pressed (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.

Choosing Options with CheckBox

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.

Image

Figure 2.9. CheckBox controls displayed on application startup (left), price displayed when the first and last CheckBox controls are selected (middle), and price displayed when the last two CheckBox controls are selected (right)

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.

Listing 2.17. The activity_check_box_app.xml File


<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 CheckBoxes 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.

Listing 2.18. The CheckBoxAppActivity.java File


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 CheckBoxes 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.

Choosing Mutually Exclusive Items Using RadioButtons

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 RadioButtons:

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.

Listing 2.19. The activity_radio_button_app.xml File


<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.

Listing 2.20. The RadioButtonAppActivity.java File


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).

Image

Figure 2.10. RadioButton controls displayed on application startup (left), TextView displaying the message when the Five Star RadioButton is selected (middle), and TextView displaying the message when the Three Star RadioButton is selected (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.

Listing 2.21. The activity_radio_button_app.xml File with Two RadioGroup Controls


<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 RadioGroups 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.

Listing 2.22. The RadioButtonAppActivity.java File


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).

Image

Figure 2.11. RadioButton controls in two RadioGroups (left), TextView informing that the Five Star RadioButton and the Grand Suite Room RadioButton are selected (middle), and TextView informing that the Three Star RadioButton and the Grand Suite RadioButton are selected (right)

Summary

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.

..................Content has been hidden....................

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