Chapter     9

Adding Interactivity: Handling UI Events

In this chapter, we will explore how to wire those super-cool UI designs that you have seen in the previous chapters, so that your UI design becomes highly functional within your Android application. You worked briefly with event handling in the last section on Dialogs in Chapter Seven, so we’ll give you the foundation in this chapter to be able to handle all types of events within the Android OS.

With Android’s convenient event listeners, you can easily add in your own custom programming logic. Using the event handling described in this chapter, you’ll be able to have your UI and graphical elements actually do something productive or impressive after they are tapped on (touchscreen), navigated to (navigation keypad), or typed into (keyboard).

We’ll begin with an overview of how Android listens to its touchscreen and keyboard, and how to harness the power of input devices.

An Overview of UI Events in Android

The way that we talk to all of the input devices in Java, and thus in Android, is via events for each type of input device (touchscreen, keyboard, and navigation keys). Events are actually system-generated messages that are sent to the View object whenever a UI element is accessed in some fashion by a user. Event refers to something that you attend or otherwise recognize as being significant, and thus is the perfect term for these UI occurrences via Android input devices.

Listening for and Handling Events

Handling and handlers are two other terms used in conjunction with events in Java and Android. Once these events are triggered by a user’s touch, keystroke, or navigation key, they must be handled within your application. This is accomplished inside a method (such as onClick() or onKeyDown()) that specifies exactly what you want to happen when one of these input events is detected by Android and is sent over to your appropriate event handler for processing.

This concept of handling events is termed listening in Android. You will see the terms event listeners and event handlers throughout this chapter. That’s because they are what the chapter is all about: how to put into place the proper event listeners and event handlers to cover your app users’ interaction via touchscreen, navigation keys, and keyboard input devices that are part of an Android device’s hardware, whether it be a smartphone handset, an iTV set remote control, or a tablet or e-reader touchscreen.

Handling UI Events via the View Class

Each of the UI elements in your application is a View object widget of one incarnation or another, and each has events that are unique to that element. This is how user interaction with specific UI elements is kept separate and well organized. Each of these View objects keeps track of its own user-input events via event handlers.

The way that a View object within your layout talks with the rest of your application program logic is via a public callback method that is invoked by Android when a given action occurs in that UI View object. For instance, if a Button widget is touched, an onClick() method is called on that object because Android knows to call a method of that name when that event occurs. In other words, Android calls back to the object that received an event so that the object can handle it via custom Java code that you write depending on what you want that object to do.

For this callback message to be intercepted by your Java code and program logic, you need to extend your View class and override the method from the View class that your UI widget was spawned (subclassed) from. To override a method means to declare and define that exact method name specifically within your class, and have it do something via your own custom program logic.

Because your UI design is made of a collection of View objects (UI widgets) laid out in one or more ViewGroup layout containers, you can see how this might represent a gaggle of coding just to make sure all of your UI elements are properly listening to the keyboard, touchscreen, and navigation keys. Has Android done anything here to make things easier on us, as it has in other areas of application development?

Yes, Android has provided a way to facilitate event handling. The View class from which all of our UI widgets are subclassed contains a collection of nested interfaces featuring callbacks that are far easier to define, as they are part of the system that makes up the View class and all of its methods.

These nested interfaces that are already a part of all of your View class-based widgets are called event listeners. They provide the easiest way to quickly set in place code that will capture user-input events and allow them to be processed right there within your application program logic.

Event Callback Methods

In the most simple of terms, an event listener is a Java interface in the View class that contains a single callback method to handle that type of user-input event. When you implement a specific event listener interface, you are telling Android that your View class will handle that specific event on that specific View object (widget).

These callback methods are called by Android when the View object that the callback method is registered to is triggered by the user-input device used to access that UI interface element. (I like to say the method is wired up to the View object, but then again, I am a programmer and drink far too much exotic coffee.)

The callback methods that we are going to cover in this chapter are the most common ones used in Android application development. They are listed in Table 9-1.

Table 9-1. Common Android Callback Methods

Method From Triggered by
onClick() View.OnClickListener Touch of screen or click of navigation keys
onLongClick() View.OnLongClickListener Touch or Enter held for 1 second or longer
onKey() View.OnKeyListener Press/release of key on phone or iTV remote
onTouch() View.OnTouchListener Touch, release, or gesture events
onFocusChange() View.OnFocusChange Focus change
onCreateContextMenu() View.OnCreateContextMenuListener Context menu

In the table, two of the methods are not directly triggered by user input, but they are related to input events. These are onFocusChange() and onCreateContextMenu(). The onFocusChange() method tracks how the user moves from one UI element to the next. The term focus refers to which UI element the user is using or accessing currently. When a user goes from one UI element to another one, the first UI element is said to have “lost focus,” and the next element is said to now “have the focus.” The onCreateContextMenu() method is related to the onLongClick() callback method, in the sense that context menus in Android are generated via a long-click user action. This is the touchscreen equivalent of a right-click on most computers, and is used for context-sensitive menus such as those right-click menus that we have been using frequently in the Eclipse Project Explorer pane.

To define one of these callback methods to handle certain types of events for one of your View objects, simply implement the nested interface in your activity or define it as an anonymous class within your application. If you define it as an anonymous class, you pass an instance of your implementation of the listener to the respective setListener() method, as you’ll see in the next section.

In the rest of this chapter, you’ll learn how to leverage the primary event listeners in Android, so that you can make your application interactive and useful.

Handling onClick Events

The onClick() method is triggered when the user touches a UI element. As you might guess, it’s the most commonly used event handler out there. So, it only makes sense to start with handling onClick events.

Implementing an onClick Listener for a UI Element

First, let’s create an anonymous OnClickListener:

final OnClickListener exampleListener = new OnClickListener()
{
    public void onClick(View arg0) {
        //Code here that does something upon click event.
    }
};

This is an example of an anonymous class. This line of code sets up a variable called exampleListener as a new OnClickListener object, which listens for onClick events.

Note  Recall from Chapter 7 that a final variable cannot be reassigned a value once it has been set. This ensures that another listener does not get assigned.

It is logical, then, that inside this class definition there would be a public onClick(View arg0) handler to handle the onClick event. The public onClick handler is passed an ID reference to the View object that was clicked on, so that it knows which View object to handle. Note that the View that has been clicked is named arg0, so if you want to reference the View object in the code inside this method, it is ready to go and must be referenced via a variable “arg0.” The first argument used in coding terminology would be called argument zero (arg0) as in computers we start counting from zero and not from one like we learned in school. The second argument used would be arg1 and so on.

How any given onClick handler handles a click event is up to the code inside of the onClick handler. That code basically explains what to do if that UI element was clicked on or touched, or typed with a keystroke.

If you want to come off as really cool right now, simply look up casually from the book and exclaim to your family, “I’m coding an onClick event handler in Java right now,” and then look back down and continue reading.

We have defined an OnClickListener, but we need to wire it to a UI element (attach it to a UI View object) before that code can be triggered. Usually, this will go inside the onCreate() method (which you have become familiar with in the first two-thirds of this book).

It takes only two lines of code to connect a button to the exampleListener object. The first is simply our XML declaration of the Button UI object in our activity_main.xml UI layout definition:

<Button android:text="First Button" 
        android:id="@+id/firstButton"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

The second line is where we connect the button construct with the event listener construct, by using the Button widget’s setOnClickListener() method, like so:

Button exampleButton = (Button)this.findViewById(R.id.firstButton);
exampleButton.setOnClickListener(exampleListener);

Adding an onClick Listener to an Activity in Android

You will probably not be surprised when I tell you that there is an even sleeker way to define your event listeners for your activities, using even fewer object references and fewer lines of code. This is normally how you will want to do things in your Android applications programming activities, so this is how we are going to do them in all of the examples in this chapter.

You can implement an event listener directly inside the declaration of your activity, within the actual class declaration. Wow. Event listeners must be muy importante.

Here is a class declaration that uses the implements keyword to embed an OnClickListener directly into the class via its declaration:

public class MainActivity extends Activity implements OnClickListener() {...}

The previous two lines of code declaring the Button and wiring via setOnClickListener() would still exist inside the onCreate() code block, but the declaration of the exampleListener object and class would not be necessary.

Now it’s time to create our EventHandling project folder and implement a button and an onClick() listener so that you can see event handling in action.

Creating the Event Handling Examples Project in Eclipse

For our first example, we’ll set up a top-level button so that when it is clicked, the text in a TextView below it changes.

In Eclipse, close the GraphicDesign project folder (right-click on it in Package Explorer and select Close Project) if it’s still open. Also, close all the empty tabs at the top of the Eclipse IDE, using the x icons in the top-right side of each tab. Now we’re ready to create our new Android Application Project.

  1. Select File image New image Project and choose Android Application Project to open the New Android Application Project series of dialogs as we have done before.
  2. Fill it out as follows (and shown in Figure 9-1):
    • Project name: Name the project EventHandling.
    • Build target: Choose Android 4.1.
    • Application name: Name the application EventHandling.
    • Package name: The package name should be fifth.example.eventhandling.
    • Create custom launcher icon: Check this box.
    • Min SDK version: Set this to 8, which matches the Android 2.2 recommended build target and is the default setting.

      9781430247883_Fig09-01.jpg

      Figure 9-1 .  Creating the EventHandling Android project using the New Android Application series of dialogs

  3. Accept the default settings in the remaining three dialogs as we did in Chapters 4 through 8.

Editing the MainActivity.java File

Now let’s edit the java code:

  1. In the Package Explorer, open your project tree hierarchy by clicking the arrows next to the /src and /res folders, so that you can see their contents. Select the MainActivity.java file under the /src/fifth.example.eventhandling folder by clicking once on it (it will turn blue), and then hit the F3 key on your keyboard. This is the keyboard shortcut for the Open option.
  2. Notice that some code has been written for us. The first thing we need to do is to implement an OnClickListener. Add implements OnClickListener to the end of the class declaration, as shown in Figure 9-2, like this: public class MainActivity extends Activity implements OnClickListener {…}

    9781430247883_Fig09-02.jpg

    Figure 9-2 .  Editing MainActivity.java to implement the onClickListener functionality

  3. As you can see in Figure 9-2, after we type in the “Implements onClickListener” and Eclipse adds our import statement for the onClickListener Class, Android Developer Tools (ADT) and Eclipse alerted us that something is amiss. If you hold the mouse over the red X on the left margin of the coding pane, Eclipse will tell you what it thinks is wrong. Click on the red X and the MainActivity class is highlighted in blue. When you mouse-over the MainActivity keyword highlighted in the class definition, up pops a helper box (shown in Figure 9-2) saying that Eclipse wants to see the unimplemented onClick() method. To fix this, double-click the Add unimplemented methods link (the first one), and Eclipse will add the method and its @override for you (see Figure 9-3), as follows:
              @Override
              public void onClick(View arg0) {
                      // TODO Auto-generated method stub
     
              }

    Note  Because the onClick code uses a View object, Eclipse imports android.view.View, which is shown at the top of the file.

  4. There is nothing better than having our IDE write code for us. Notice that when we had Eclipse write our onClick( ) method that it also imported the android.view.View Class, so both of the classes we will need for Event Handling for Clicks have been added. This is all highlighted at the top of Figure 9-3.

    9781430247883_Fig09-03.jpg

    Figure 9-3 .  Implementing an OnClickListener in our class definition via the implements keyword

    Note  You need to get used to looking at what Eclipse is telling you as you code. This awareness is especially useful while you are learning the programming language and are inside the development environment. That is why I am showing you some of these automatic coding functions here in this book, rather than writing perfect lines of code every time in exactly the correct order. One of the things you need to master is your process of working within the Eclipse IDE and paying close attention to what it is telling you. If you mouse-over or click on the things it flags or highlights, you will get pop-up windows as well as tool-tips containing additional helpful information.

  5. Now let’s define our Button and attach our setOnClickListener() to it as we did earlier in Figure 9-4. We talked about this earlier in the chapter, but this time, the containing activity is the event listener, so we use this to refer to the containing object.
               Button button = (Button)findViewById(R.id.button1);
               button.setOnClickListener(this);

9781430247883_Fig09-04.jpg

Figure 9-4 .  Adding the Button widget and setOnClickListener() method in Eclipse

This is all shown in Figure 9-4, along with the import android.widget.Button; statement that we need to use the Button in our code. Next, we will add the Button UI element to our RelativeLayout, using the Eclipse Graphical Layout Editor (GLE), and then hand modify the XML code to place it above our text, so that it’s more intuitive for the end-users. This will remove any flags in our Java code editing pane that tell us that a button1 XML object definition does not yet exist! The first step in this process is shown in Figure 9-5.

9781430247883_Fig09-05.jpg

Figure 9-5 .  Creating a Button in /res/layout/activity_main.xml via the Graphical Layout Editor in Eclipse

Editing the activity_main.xml File

Now it’s time to set up the XML mark-up in our activity_main.xml file in the /res/layout/ folder.

  1. Select the activity_main.xml file under the /res/layout folder and hit F3 to open it in the IDE in its own tab, or use right-click (on the activity_main.xml file) and the Open menu selection to open it that way instead.
  2. Click the Graphical Layout Editor tab at the bottom of the IDE to show the layout visually (see Figure 9-5), Then drag the Button widget (shown selected and being dragged in Figure 9-5) onto the screen to the right, and drop it into place under the TextView widget. Make sure the tool-tip says centerHorizontal=true as well as alignParentTop=true and margin=50dp as shown in the screen shot in Figure 9-5.
  3. Now click the activity_main.xml tab at the bottom of the IDE to switch the view from visual layout to XML coding view. Cut and paste the Button code so that it comes before the TextView code (but after the RelativeLayout tag). The Button should be the first thing at the top of the screen.
  4. Now open the /res/values/ folder and right-click on the strings.xml file and select Open and then use the Properties Editor to change the Hello World default text string to use variable name button_caption and a text value of: CLICK TO GENERATE EVENT as shown in Figure 9-6.

    9781430247883_Fig09-06.jpg

    Figure 9-6 .  Editing the button_caption string property to read CLICK TO GENERATE EVENT

  5. Now click the strings.xml XML editor tab at the bottom of the middle editing pane and duplicate the text string (or use the Add … button, shown in Figure 9-6, and add the second variable via the Visual Resources Editor) for the text output. Name the variable text_message and set its value to: NO EVENT RECEIVED YET as shown in Figure 9-7.

    9781430247883_Fig09-07.jpg

    Figure 9-7 .  The strings.xml file after the EventHandling project’s related text string tags have been added

  6. Add the android:text @string XML variables, text message TextView object ID and the button1 Button object ID, and the centering attributes that you learned about in the previous chapters shown in Figure 9-8. Note that the Graphical Layout Editor added all of the android:layout_ parameters for you based on how you dragged and dropped the button earlier. Pretty cool. Here is what the final code should look like:
 
<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" >
    
<Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"
        android:text="@string/button_caption" />
 
<TextView
          android:id="@+id/textmessage"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_centerHorizontal="true"
          android:layout_centerVertical="true"
          android:text="@string/text_message"
          tools:context=".MainActivity" />

</RelativeLayout>

9781430247883_Fig09-08.jpg

Figure 9-8 .  Editing Button and TextView object parameters in our /res/layout/activity_main.xml file

Updating MainActivity.java

Now let’s go back into our Java code.

  1. Click the MainActivity.java tab at the top of the code editor pane.
  2. Add the code that responds to a click on the button, as follows (see Figure 9-9):
        public void onClick(View arg0) {
                TextView text = (TextView)findViewById(R.id.textmessage);
                text.setText("BUTTON HAS BEEN CLICKED. EVENT PROCESSED.");
        }

9781430247883_Fig09-09.jpg

Figure 9-9 .  Defining the onClick() event handler code for a TextView in MainActivity.java

We add our TextView object declaration into onClick(). We also add a setText("BUTTON HAS BEEN CLICKED. EVENT PROCESSED.") call to the TextView object we named text, created in the previous line. Finally, we add an Import android.widget.TextView; statement, or we have Eclipse do it for us, via the error-warning icon mouse-over work process. You’re getting pretty good at this, aren’t you?

Running the Event Handling Examples App in the Emulator

To run this example, right-click your EventHandling folder in the Package Explorer pane and select Run As image Android Application. We have our first UI that responds to the most common event handler out there: the onClick handler. Figure 9-10 shows the results.

9781430247883_Fig09-10.jpg

Figure 9-10 .  Running the onClick( ) event handling example in the Android 4.1 emulator

Android Touchscreen Events: onTouch

Android handsets that feature touchscreens—the vast majority of them today—can take advantage of advanced touchscreen features, such as gestures.

Note  Gestures are movements with the user’s finger across the touchscreen that invoke certain program functions. They are popular for interaction on large screen smartphones and tablets. You will want to learn about implementing gestures when you become a more experienced Android developer. Gestures became available in Android 1.6, and thus they do work in Android 2.2, which is the recommended minimum SDK version that we are developing for in this book to provide a wider audience of user compatible devices. However, coding to the Gestures API is a bit too advanced for this Absolute Beginner book.

It is important to note that an onClick event handler also works on a touchscreen, but an onTouch handler does NOT work with the navigation keys or selector key (the center selector Enter key).

Therefore, it may well be wise to use the onClick() method for your apps for most UI operations for the widest compatibility, and use onTouch() specifically when working with more advanced touch events such as gestures that involve only the touchscreen.

Because we have already covered implementing onClick(), we’ll continue here with the other important event handlers. These are the ones you will use most frequently in your application design and coding: onLongClick, OnKeyUp, onKeyDown, onCreateContextMenu, and onFocus, along with onClick as the most often used.

Android’s Right-Click Equivalent: onLongClick

After OnClick, OnLongClick is the next most used interface event. It is generated by most input hardware and is also the basis for the context menu in Android.

The onLongClick() method works in the following scenarios:

  • When the user touches and holds on the touchscreen for 1 second or longer
  • When the user holds down the Enter key on the phone for 1 second or longer
  • When the user holds down the center navigation key for 1 second or longer
  • When the user presses and holds down the Trackball for 1 second or longer

Any of these will generate an OnLongClick event for whatever UI widget currently has the focus or, in the case of a touchscreen, is underneath the area of the screen being touched (or long-touched, in this instance!).

Because any View object can trap an onLongClick() callback, the most elegant way to show this event handling is to add it to our Button UI object in our current EventHandling example code. This also will allow you to see the common scenario of more than one type of handler being used right alongside other types of event handlers in the same View and class.

  1. In MainActivity.java, add a comma after OnClickListener in the public class MainActivity definition and add OnLongClickListener, as shown in Figure 9-11. Then mouse-over the red-underlined OnLongClickListener and select the option to add the import statement (boom bam—there is our import code for this listener). Then mouse-over the red-underlined MainActivity class name and select the link to add unimplemented methods. Voila, we now have the following:
        public boolean onLongClick(View arg0) {
            // TODO Auto-generated method stub
            return false;

        }

    9781430247883_Fig09-11.jpg

    Figure 9-11 .  Implementing an OnLongClick listener in the MainActivity.java class

  2. Now copy the text object and text.setText() code from the onClick handler and paste it into the onLongClick handler, where the placeholder comment code is. Change the text message to reflect the hold and long-click, as shown in Figure 9-12. Note that we can use the same object name text in both handlers. Because it is a local variable to each handler, neither text object sees the other reference. Finally, wire the OnLongClick handler to the button using the button.setOnLongClickListener(this); method call just like we did with the setOnClickListener() method earlier.

    9781430247883_Fig09-12.jpg

    Figure 9-12 .  Attaching an OnLongClick listener to our Button object in MainActivity.java

  3. Now try the new functionality. Right-click the EventHandling folder and choose Run As image Android Project. This time, you get an app that displays one message when you click and another when you hold the click. But when you release the long-click, the onClick message appears. The onLongClick message does not stay on the screen. Why is this?
  4. Well, we forgot to change the default onLongClick() code, which returns false. This tells Android that nothing has been handled in that code block, so we are happy for Android to pass the event on to any other handlers that might be interested. But we don’t want this to happen in our example. Instead, we need to return true when we handle the event, as follows (see Figure 9-13):
    public boolean onLongClick(View arg0) {
        TextView text = (TextView)findViewById(R.id.textmessage);
        text.setText("BUTTON HAS BEEN HELD. onLongClick EVENT PROCESSED.");
        return true;
    }

9781430247883_Fig09-13.jpg

Figure 9-13 .  Returning a true flag from our EventHandling Project’s onLongClick() method

This tells Android that we have handled the event successfully, and sets the text that we wanted.

Some of the event handlers return a Boolean (true or false value) to tell the calling code whether your listener has handled the code (or consumed the event, as the programming terminology goes). So return true if you have handled the event (in our case, setText() has been done) and processing should stop here. Return false if you have not handled it, or if you want the event to “bubble up”—that is, to be passed on (up) to other event handlers, even if it has been handled.

Now compile and run our OnLongClick app version. It works perfectly. A click displays the proper message and stays on the screen, and a long-click displays the proper message that stays on the screen until a short-click changes it back again.

Now let’s add an onKeyListener and trap some keystroke events.

Key Event Listeners: onKeyUp and onKeyDown

Events that will become familiar to you in Android app programming are onKey, or onKeyUp (key released) and onKeyDown (key pressed down). Key is short for keyboard, but more and more Android devices do not feature a traditional computer keyboard (unless you have a Bluetooth external keyboard as an accessory) but some still do have smaller sets of keys (a mini keyboard) or in the case of GoogleTV possibly some sort of remote control that has keys. Some iTVs may even come with a wireless keyboard, so this is an important event to handle for many Android applications.

These onKey() events are commonly used for games and to implement keyboard or keypad shortcuts in your application, much like the F5 shortcut that we use in Eclipse for Refresh or the F3 shortcut we use for Open.

To show how easy the keyboard event listeners are to implement, we are going to add a couple more lines (OK, a dozen more) to our Java code to listen for a key event (the center keypad hardware key, found on every Android Device).

9781430247883_Fig09-14.jpg

Figure 9-14 .  Having Eclipse Add our KeyEvent import statement for us

Adding the Java for Keyboard Events

In our MainActivity.java file, we want to add one simple import statement and two basic blocks of code that will allow us to handle keyboard events via the OnKeyDown handler. We will only add about a dozen lines of code to be able to handle key events in our current EventHandling Project. We are using one EventHandling project for all our code in this chapter to show how all the different types of Android Event Handling can coexist peacefully in a single application and so that you get experience writing more complex apps with more than one hundred lines of code.

Here is the code that we will need to add to the bottom of our current EventHandling Project’s Java code (see Figure 9-15):

 
        public boolean onKeyDown(int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
                            textUpdate();
                            return true;
                    }
                        return false;
                }
 
        public void textUpdate() {
                TextView text = (TextView)findViewById(R.id.textmessage);
                text.setText("CENTER KEYPAD KEY PRESSED");
        }

}

9781430247883_Fig09-15.jpg

Figure 9-15 .  Adding an onKeyDown listener and textUpdate( ) method to our MainActivity class Java code

We need to import android.view.KeyEvent for the onKeyDown handler (first code block) or we can let Eclipse do it for us while we are writing the onKeyDown handler method (this is shown in Figure 9-14 ). We don’t need to import android.widget.TextView for the textUpdate() method that we write in our second code block, because we are already using a TextView widget in our current application, and will use that TextView to display the text that our onKeyDown( ) handler sets.

We will leave the class declaration and the onCreate() and onClick event handling blocks of code  exactly as they are.

The first block of code we write is the onKeyDown handler, which is a public method that returns a Boolean value that tells us if the event was handled (true), or not handled and needs to be passed along (false). The onKeyDown() method takes two parameters: the keyCode (the key that was pressed) and details of the event (event).

Our program logic inside the onKeyDown handler first looks at the keyCode passed into the handler. If it is equal to the center keypad hardware keyCode, signified by the KEYCODE_DPAD_CENTER constant, it runs the textUpdate() method, and then returns true to signify that we handled the event. Otherwise, onKeyDown() returns false to signify that an event was not handled.

This is the first time we have written our own method: the textUpdate() method that is called from inside onKeyDown(). This demonstrates some standard Java programming. The two lines of code that are in the textUpdate() routine could have been written where the textUpdate(); line of code is inside the onKeyDown() handler, like this:

public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
                          TextView text = (TextView)findViewById(R.id.textmessage);
                          text.setText("CENTER KEYPAD KEY PRESSED");
                          return true;
        }
            return false;
        }

In actual programming practice the textUpdate() method can (and will) contain all of the various things that you want to do when someone clicks the center keypad hardware key. You can use this method to contain all of your code statements, rather than putting them all inside the onKeyDown handler, where they could be in among actions for other keys. Doing it this way simply makes things more organized and modular, and really comes in very handy when you get into more complex code constructs, so we are teaching you to write your own method (and call it) here for this reason.

Finally, you might be wondering why there is an onKeyUp and onKeyDown, rather than just one onKey listener. As you might imagine, onKeyDown is sent when the key is pressed down, and onKeyUp is sent when the key is released. The reason both are supported is because some applications need to know when a given key is being held down (like the repeating characters feature in a word processor) and for how long, thus in that application the code would look for both the onKeyDown (repeat these functions while onKeyDown) and onKeyUp (stop doing the functions now) events, and handle them with different code.

Now let’s compile and run the application.

You’ll see a text field that says “NO EVENTS RECEIVED YET” that changes after you click down the center keypad hardware key in the emulator (shown on the right in blue in Figure 9-16).

9781430247883_Fig09-16.jpg

Figure 9-16 .  Pressing center keypad Button in 4.1 Emulator to send onKeyDown event

Tip  If you want to detect a range of keystrokes and send them to different custom methods, a good programming construct to use is the switch construct, which allows you to outline different cases from which to select. We used switch in Chapter 7’s examples.

Context Menus in Android: onCreateContextMenu

The concept of the context menu is a very clever one. Unfortunately, it is often underutilized in PC, tablet, iTV, e-reader, and smartphone applications. Fortunately, Android provides us all the prebuilt classes we need, as well as a special event, to make implementing context-sensitive menus in our apps as easy as possible to code. Why does Android do this for us? It is because Google has a vested interest in making their Android OS and apps as easy to use and as standardized as possible.

A context menu should provide quick and easy access to all application functions related to a given UI object. For instance, when I right-click here in my word processor, I get a context-sensitive menu with options for cut, copy, paste, font, paragraph, bullets, numbering, styles, hyperlinks, lookup, synonyms, and translate.

The context menu in Android is always accessed by the LongClick event (covered earlier in the chapter), just as on a PC it is always accessed via a right-click of the mouse.

To demonstrate, we will add context menus to this chapter’s example project. We’ll add two classes, along with two custom methods, to implement our context menus. We’ll take a look at the Android Toast widget, which is very handy to use to blast quick little messages to the user. This way, you don’t need to use a full-blown dialog implementation, as we learned about in Chapter 7, and in this way we can learn about a different and new widget at the same time.

Adding the XML for Context Menus

First, let’s add a second Button tag to our activity_main.xmlRelativeLayout so that we have a UI element (button) to use to access our Context Menu.

  1. Click the activity_main.xml file in the /res/layout/ folder and hit the F3 key to open it in the Eclipse central editing pane, and then click the Graphical Layout Editor tab at the bottom of that pane. Now drag a Button View out onto to the pane, and center it under the TextView, exactly as we did in Figure 9-5 earlier in the chapter, and with exactly the same parameters.
  2. Once the button appears under your text, switch back into XML editing mode via the activity_main.xml tab at the bottom of the pane. Now we’ll edit our Button tag attributes. The first one is android:text. Let’s add a context_button_caption name and a  "Long-Click for Context Menu" value to a <string> tag in our /res/values folder strings.xml file and reference it with the Button tag parameter android:text=”@string/context_button_caption” and we’ll use the GLE generated Button object ID of button2 because it’s our second button.
  3. Let’s also center our button using the android:layout_centerHorizontal = "true" attribute, as we have done previously. GLE can also do this for us via tool-tip feedback.
  4. Make sure that the RelativeLayout positioning tag android:layout_below references the textmessage object.
  5. Finally, make sure that the android:layout_marginTop is set to the same 50dp that the button1 object uses, so we keep our spacing even and professional looking.

Here is what your XML tags should look like (see Figure 9-17):

<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">
           <Button
                android:id="@+id/button1"
                android:text="@string/button_caption"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="50dp"
                android:id="@+id/contextButton" />
 
          <TextView
                android:id="@+id/textmessage"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontaltrue"
                android:layout_centerVertical="true"
                android:text="@string/text_message"
                tools:context=".MainActivity" />
 
          <Button
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/textmessage"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="50dp"
               android:text="@string/context_button_caption" />
 
</RelativeLayout>

We will reference the textmessage and button2 inside our Java code.

9781430247883_Fig09-17.jpg

Figure 9-17 .  Adding a second Button object in our activity_main.xml file to receive the long-click event

Adding the Java for Context Menus

The main two Java methods that we override are onCreateContextMenu() and onContextItemSelected(), which replace Android’s default methods of the same name. The use of the super object in the first one allows us to reference a method in the parent class that we are overriding. Note that overriding does not replace a class; it just allows us to customize it, leaving the original class that was extended intact and usable. This also leaves us a lot less code to write, as none of the code written in (for) the superclass is revisited.

Now let’s add the code for our onContextMenu event handling in MainActivity.java. We’ll add the new code in with the previous code that we wrote, right before the onKey() section we added to handle onKeyDown events.

First, we need to use an import statement to import the Java classes that we are going to reference in the code we are about to write, or we can just write the code into Eclipse and let Eclipse add the import statements. Three of the six relevant import statements for this code are related to our UI elements (android.view.View, android.widget.Button, and android.widget.Toast), and the other three are related to our implementation of our LongClick context menu. Some of the import statements relating to what we are going to do with Context Menus are already in our code so far. The four that will need to be added (or will be added by Eclipse, if you forget to add them) are:

import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.widget.Toast;

ContextMenu contains the methods that are related to the top level of the menu, such as what it is called, how it looks, and so forth. ContextMenuInfo relates to the information about any one given ContextMenu, which is really a collection of options. Within that container or level, we have the MenuItems, which are their own level of objects. Each MenuItem can have a name and styling, and can call methods once it is selected.

Now, let’s see how Android attaches our UI element to a ContextMenu.

First, we need to add two key lines of code to our onCreate() method for our activity. The first declares and establishes a Button object, which we call Button2 and find by its button2 ID from the activity_main.xml file. The next line of code wires our newly created Button2 Button object to the ContextMenu system in Android.

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button Button2 = (Button) findViewById(R.id.button2);
        registerForContextMenu(Button2);
    }

Tip  When I first started working with Android, I wondered which class contained the registerForContextMenu() method. To again demonstrate how to use Eclipse as a learning tool, I’ll tell you how to answer a question like that. Place your cursor over the method you are interested in and a box full of information about the method in question will pop up in Eclipse including the class that contains the method. In Eclipse you will find that mouse-over and right-click are very helpful in researching what is going on, especially in relation to error flags and warning icons (left-click on these as well to reveal potential solutions).

Now let’s get into our custom logic for creating our ContextMenu and its content. The first of the two menu methods is onCreateContextMenu(), which takes three objects as parameters:

  • The ContextMenu object named menu
  • The View object (UI widget) that called it
  • The ContextMenuInfo object named menuInfo, which contains information about the menu configuration

The first line of code inside this code block simply passes our three parameters up to the parent class, which is referenced via the super keyword. The next three lines of code call methods against (or invoke methods on) the menu object, which is of type ContextMenu. This code is configuring our top-level ContextMenu object by giving it a title using menu.setHeaderTitle() and adding two menu items via the two menu.add() methods.

    public void onCreateContextMenu(ContextMenu menu, View view,
                                    ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, view,  menuInfo);
        menu.setHeaderTitle("Android Context Menu");
        menu.add(0, view.getId(), 0, "Invoke Context Function 1");
        menu.add(0, view.getId(), 0, "Invoke Context Function 2");
    }

Shown in Figure 9-18 is the screenshot of Eclipse after adding the code, and the screenshot shows how Eclipse flags and then suggests and even adds our import statements for the ContextMenu and ContextMenuInfo classes. You should be getting used to this work process by now!

9781430247883_Fig09-18.jpg

Figure 9-18 .  Adding onCreateContextMenu( ) and importing ContextMenu and ContextMenuInfo classes via mouse-over

The second context menu method is onContextItemSelected(), which is passed a single parameter of type MenuItem named item. Note that this method has a Boolean return type, which means we need to return a true (handled) or false (not done yet) reply.

To start with, we have an if-then-else loop that compares the title of each MenuItem to a string. If the title matches, it runs the appropriate contextFunction1 or contextFunction2 (which we will code next).

    public boolean onContextItemSelected(MenuItem item) {
        if(item.getTitle().equals("Invoke Context Function 1")) {
              contextFunction1(item.getItemId());
        }
        else if(item.getTitle().equals("Invoke Context Function 2"))  {
              contextFunction2(item.getItemId());
        }
        else {
              return false;
        }
        return true;
    }

Recall that the first code after the if in parentheses is the condition. It reads, “If the title that we are getting from the item object is equal to the text string 'Invoke Context Function 1', then perform the statements in the curly braces that follow this conditional statement.” Note that this could also be written as: if(item.getTitle( )==“Invoke Content Function 1”); however using the .equals() method is considered a better programming practice when comparing String values.

Note  Remember that == (two equal signs) means is equal to, and compares two integer or string values to each other, and = (one equal sign) means to set the value of a variable or constant to another value, so that is setting a value rather than simply comparing two values to see if they are the same or if they are different. What we are using here for ContextMenu is the .equals() method, which is considered “Best Practices” for comparing String values, and can also be chained, so we are using it here to show you both Java comparison operation solutions in a single chapter!

If this does not equate to true for the first if condition, then the next else block is encountered, along with a second (nested) if statement that is almost completely identical to the first, except that it is looking for the 2 option rather than 1. If this also is not satisfied or matching, the second else returns a false from the method to the calling code, telling it, “Sorry, no menu options here that match that!” If one of the if condition is met, the true, which is under the conditional code block is returned because we have not jumped out of the method by returning a value yet.

Type this code into Eclipse and when Eclipse flags the MenuItem class as needed to be imported, use the usual work process shown in Figure 9-19 to add the import statement, and then we’ll be ready to write our own custom methods that are called in the onContextMenuItemSelected() method that we just wrote.

9781430247883_Fig09-19.jpg

Figure 9-19 .  Adding an onContextItemSelected() method and importing a MenuItem class

Now we need to write our own methods for the two options, which we’ll call contextFunction1() and contextFunction2(). We declare these methods as public and as void, as they do not return any values. They simply carry out a task with no result to report back. We name the first method contextFunction1() and define one integer data parameter to pass, in this case an ID.

    public void contextFunction1(int id){

Inside this method, we make a call to the Toast widget, which allows us to send brief messages to our end users during their use of the application. To do this, we use the makeText() method and access it directly from the Toast class via the following one (admittedly dense) line of code:

Toast.makeText(this, "function 1 invoked!", Toast.LENGTH_SHORT).show();

This is another one of those “chaining” lines of code we talked about earlier in the book that does several things within a single code construct. Once you get really good at programming, this type of coding becomes a really great way to write more “compact” or dense code.

So we call the .makeText() method and pass it three parameters:

  • The activity that is running the Toast alert, in this case the one it’s contained in (this)
  • What the message should be, contained between quotes
  • How long (in this case, a short length of time) to show the Toast pop-up

After the Toast.makeText(), another .show() is appended. This displays (shows onscreen) the message that we just specified with makeText(). One line of code does everything. And the best part is, you can now use this same line of code to pop up little messages to your users whenever you want to do so. Grab that glass of wine on your left, and let’s make a Toast to Toast!

Note that the context menu code that we learned about earlier has nothing to do with this one-line Toast construct, which will send a message to your screen anyplace you put it in your code. Some programmers use this for debugging, with messages like, “Setting X variable to 7 at (System Time)” or similar, so that you can see on the screen a visual progress of your app running through its code logic.

After our contextFunction2 code construct, which is very similar to contextFunction1, we have our key event handlers from the previous section working at the same time as our ContextMenu. Once you write these two methods into Eclipse, be sure to note the flags that tell you that you need an import statement to use the Toast class, and use the usual work process shown in Figure 9-20 to have Eclipse insert the import statements needed for you.

9781430247883_Fig09-20.jpg

Figure 9-20 .  Adding our two custom methods and having Eclipse import the Toast class for us

The entire body of code in MainActivity.java should now look like the following (see Figure 9-21).

package fifth.example.eventhandling;
 
import android.os.Bundle;
import android.app.Activity;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android. view.View.OnLongClickListener;
import android.widget.Button;
import android.widget.TextView;
 
import android.widget.Toast;
 
public class MainActivity extends Activity Implements OnClickListener, OnLongClickListener {
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button1);
        button.setOnClickListener(this);
        button.setOnLongClickListener(this);
        Button button2 = (Button) findViewById(R.id.button2);
        registerForContextMenu(button2);
    }
 
    
    public void onCreateContextMenu(ContextMenu menu, View view,
                                    ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, view, menuInfo);
        menu.setHeaderTitle("Android Context Menu");
        menu.add(0, view.getId(), 0, "Invoke Context Function 1");
        menu.add(0, view.getId(), 0, "Invoke Context Function 2");
    }
 
    
    public boolean onContextItemSelected(MenuItem item) {
        if(item.getTitle().equals("Invoke Context Function 1")) {
                contextFunction1(item.getItemId());
        }
        else if(item.getTitle().equals("Invoke Context Function 2")){
                contextFunction2(item.getItemId());
        }
        else {
                return false;
        }
        return true;
    }
 
    public void contextFunction1(int id){
        Toast.makeText(this, "function 1 invoked!", Toast.LENGTH_SHORT).show();
    }
 
    public void contextFunction2(int id){
        Toast.makeText(this, "function 2 invoked!", Toast.LENGTH_SHORT).show();
    }
    public boolean onCreateOptionsMenu (Menu menu) {...}
    public void onClick (View arg0) {...}
    public boolean onLongClick (View arg0) {...}
    public boolean onKeyDown(int keyCode, KeyEvent event) {...}
    public void textUpdate() {...}

}

9781430247883_Fig09-21.jpg

Figure 9-21 .  Adding the Java methods needed to implement a context menu in MainActivity.java

Now let’s run our code with Run As image Android Application and see how it all works together. A long-click on the button brings up the context menu. A touch or click on one of the buttons highlights it, as shown in Figure 9-22. Once it is clicked, a Toast menu tells us our method has been run. Also notice that our previous section code for onKeyDown() as well as for both onClick() and for onLongClick() all still works perfectly together.

9781430247883_Fig09-22.jpg

Figure 9-22 .  Running our application in the Android 4.1 emulator after adding a context menu

Controlling the Focus in Android

One of the most challenging aspects of UI design and programming is tracking and controlling the focus of your application. The focus is where the UI is paying attention, or focusing its attention currently, and this equates to representing which UI element the user is presently dealing with (or is using).

The tough part about focus is that you can’t always see it visually. Even as an end user, it is sometimes difficult to see where the focus is currently at within an application. We have all experienced this with our computers at one time or another, most commonly while we are filling out forms, where the active text entry cursor for a field moves or “jumps” from one field to another as the form is filled out, or as the Tab key is used to jump (or progress) the input focus from one field to the next field.

It is even more difficult to control, track, and implement focus from a programming standpoint. Note that focus is typically not something that you need to specifically worry about (Android handles it automatically), unless it is somehow tripping up your application’s user experience, or unless you want to implement finer or tighter control over how your users interface with your UI Design or Application’s UX (user experience).

Android has an internal algorithm that decides how it hops from one UI element (View or Widget) to another, based on which View is closest to the previous View, but you can also control how the focus moves from one UI element widget to the next with your own custom code. Here we will go over the basics, to get you started and familiar with the concepts, in case you need to intervene with your own XML or Java code to manually control the focus inside of your application.

First, we will look at how to control focus via XML, as that is easier to understand and implement than the Java coding route. Later, we will go over which Java methods will allow you to take focus or otherwise control the focus, based on what the user is doing in the application.

Adding the XML for Focus Control

To start, let’s add a couple more buttons to the bottom of the UI we’ve been developing in this chapter, and then we’ll set the focus to do something that is not standard focus procedure in Android.

The easiest way to do this is to copy our existing button2 tag in our activity_main.xml file and paste it in twice right more underneath our existing button2 tag markup (see Figure 9-23). You can also use the Eclipse Graphical Layout Editor and drag a couple more button elements out onto the UI layout screen, if you’d rather do it that way.

9781430247883_Fig09-23.jpg

Figure 9-23 .  Adding a third and fourth UI button to the /res/layout/activity_main.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">
 
           <Button
                android:id="@+id/button1"
                android:text="@string/button_caption"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="50dp"
                android:id="@+id/contextButton" />
 
          <TextView
                android:id="@+id/textmessage"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontaltrue"
                android:layout_centerVertical="true"
                android:text="@string/text_message"
                tools:context=".MainActivity" />
 
          <Button
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/textmessage"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="50dp"
                android:text="@string/context_button_caption" />
 
          <Button
                android:id="@+id/button3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/button2"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="10dp"
                android:text="@string/third_button_caption" />
 
          <Button
                android:id="@+id/button4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/button3"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="10dp"
                android:text="@string/fourth_button_caption" />
</RelativeLayout>

To make our Button tags unique, we also need to rename their IDs to button3 and button4, which if you use the Graphical Layout Editor will be done for you automatically, as will the centering and margin spacing of 10dp parameters. This way, we can access the buttons in our Java code and also change their display text to reflect that they are the third and fourth buttons, respectively. Make sure to add their names and values to the /res/values/strings.xml file via the <string> tag, as we did in the previous sections, and as is shown in Figure 9-27 later on in this exercise.

We will leave all of the other Button tag attributes for scaling and centering the same, and use a android:layout_marginTop value of 10dp to keep the bottom three buttons closer together.

Now we will add our android:nextFocus attributes, so that we will have control over which UI elements our focus jumps to and from when the user navigates the UI with the up and down arrow keys on the front of the smartphone, iTV remote, e-reader or tablet.

For the existing button1 tag attributes, we want to add an android:nextFocusUp attribute and point it to the fourth button. Then, if users hit the up arrow on their Android smartphone or tablet when they are on the first button, it will cycle back down to the last button, creating a seamless loop through the button stack.

Because the ID of the fourth button is button4, this tag attribute will read as follows:

android:nextFocusUp="@+id/button4"

This is done to reference the fourth button tag we have defined in our XML markup here as the destination UI element for the up arrow focus to go to if users hit the up navigation arrow when they are on (have focus on) the first UI button (button1 from our first onClick and onLongClick examples).

To control advancement of focus from the button1 to the button2 button, we add this:

android:nextFocusDown="@+id/button2"

Now we have defined all of the focus movements that can happen for the first (top) Button UI element button1, and we are ready to define the focus movements for the next three user interface buttons.

This will be a very similar process. In fact, you can simply cut and paste the two lines of code that you wrote for the first Button (button1) tag and change the ID attributes after you paste them into the next three Button element tags for button2, button3, and button4.

For the second Button tag, we will add in another two android:nextFocus attributes. This time, these point to the buttons immediately above and below the second and third button, so the middle two buttons are the easiest to code. Their code will look like the following:

android:nextFocusUp="@+id/button1"
android:nextFocusDown="@+id/button3"
 
android:nextFocusUp="@+id/button2"
android:nextFocusDown="@+id/button4"
 

For the fourth Button tag, we will add in another two android:nextFocus attributes, which finally point to the buttons immediately above and back up to the top button in our loop of buttons, as follows:

android:nextFocusUp="@+id/button3"
android:nextFocusDown="@+id/button1"

The first attribute is pretty straightforward, as the button3 button is above our fourth button. For the nextFocusDown attribute because there is no button underneath the fourth button, we actually want the focus to wrap, or loop back, to our first button1 button, so that is the ID we use in the android:nextFocusDown attribute that we add to the final Button tag.

Note  There are nextFocusLeft and nextFocusRight attributes available (one for each arrow key) if you are using a horizontal LinearLayout tag attribute, for instance, or if you have things arranged from side to side within a RelativeLayout container.

Here are the four blocks of nextFocus attributes that we added to our four buttons (we’ll omit the dozens of other parameters, so as to show only the focus-related coding) so that you can check your work (also see Figure 9-24 for the complete XML code):

<Button
        android:id="@+id/button1"
        android:nextFocusUp="@+id/button4"
        android:nextFocusDown="@+id/button2"
       (other button parameters) />
        
<Button
        android:id="@+id/button2"
        android:nextFocusUp="@+id/button1"
        android:nextFocusDown="@+id/button3"
       (other button parameters) />
                
<Button
        android:id="@+id/button3"
        android:nextFocusUp="@+id/button2"
        android:nextFocusDown="@+id/button4"
       (other button parameters) />
                
<Button
        android:id="@+id/button4"
        android:nextFocusUp="@+id/button3"
        android:nextFocusDown="@+id/button1"
       (other button parameters) />

                

9781430247883_Fig09-24.jpg

Figure 9-24 .  Controlling the focus via XML markup in /res/layout/activity_main.xml

Adding the Java for Focus Control

Now let’s declare the two new buttons we defined in our activity_main.xml markup in our Java code, and point them toward our ContextMenu code that we wrote in the previous section, so that they actually do something useful, and bring up a Context Menu when we long-click on them.

Here are the four new lines of code that we need to write to support these new buttons (see Figure 9-25), which go in the end part of our onCreate() method as follows:

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button1);
        button.setOnClickListener(this);
        button.setOnLongClickListener(this);
        Button Button2 = (Button) findViewById(R.id.button2);
        registerForContextMenu(Button2);
        Button Button3 = (Button) findViewById(R.id.button3);
        registerForContextMenu(Button3);
        Button Button4 = (Button) findViewById(R.id.button4);
        registerForContextMenu(Button4);

        }

9781430247883_Fig09-25.jpg

Figure 9-25 .  Registering our bottom two buttons for the context menu in MainActivity.java in Eclipse

To implement this in the quickest fashion, select the two lines of code that define and point our button2 object to the registerForContextMenu() method, and paste them twice below the original two lines of code.

Change the Button2 and button2 references to Button3 and button3 in the first two lines, and to Button4 and button4 in the last two lines. You have now declared all four buttons in Java and set them to actually do something in your code when they are either clicked or long-clicked on.

Now let’s use our familiar Run As image Android Application work process to compile and run this application, as shown in Figure 9-6. It now traps or handles onKey events, onClick events, and onLongClick events as well as handling onContextMenu events, and additionally implements control of focus among the usable UI elements, namely the four buttons.

9781430247883_Fig09-26.jpg

Figure 9-26 .  Running our EventHandling project application in the Android 4.1 emulator after adding focus control

You will notice now that when you compile and run this code, all three buttons at the bottom of the app will call up a ContextMenu. In your own apps, you may want all (or many) of your UI elements to bring up the same context menu selections (say the application default context menu), and this is the way that you would do that using just a very few lines of code.

If your code does not run for some reason, you can use the Eclipse Project image Clean option to “clean” your project. This regenerates the R.java class that lives in the /gen/ folder and that holds the generated (compiled) Java files for the application. Three key commands in Eclipse that you will use frequently are: Refresh, Validate, and Clean, usually in that order, to help Eclipse to troubleshoot code problems that you may be experiencing in the IDE.

The reason I mention this here is because when I first ran the focus code in this chapter, which I know is correct and bug-free, the activity would not run in the emulator, and I was getting an error in LogCat that said that I was “casting” a Button object into a TextView object. For this to have been true, I would have had to switch the FindById references for button1 (or button2, button3, or button4) with the FindById reference for textmessage in my Java code.

As this was not the case, I ran the Eclipse Project image Clean utility, which regenerated my R.java file, and fixed the problem for me. One of the tricky things about programming is that sometimes your code can be correct, and the code in the IDE or the Compiler (SDK) can have bugs in it too! Add to this the quick SDK revision cycles for Java and Android (between Version 1 and Version 2 of this book, Android went from SDK Level 3 to SDK Level 16) and programming becomes a “moving target” significantly more challenging than if it were inherently within a fixed or unchanging programming environment.

If the code still does not compile and run, you may have forgotten to add all of the string tags needed to the /res/values/strings.xml file as shown in Figure 9-27. Also shown at the bottom of the screenshot is the successful running of the app in the emulator under the Console Tab at the bottom of the IDE.

9781430247883_Fig09-27.jpg

Figure 9-27 .  Adding the Button captions in the strings.xml file and view of the Android Console tab

It is important to test your applications vigorously, as some bugs will show up only after all of the features have been used already once or twice. Let’s do that now.

To test the application, long-click on each of the buttons, and select either option. Everything should work as expected and pull up the context menu. To see the cycling focus that we have implemented, use the up or down arrow/keys in the middle of the Android smartphone or tablet (in this case, on the 4.1 emulator) to cycle the focus among the buttons (focus is shown in blue). You will notice no matter which direction (up or down arrow button) you choose, the focus cycles or loops through the buttons correctly and seamlessly.

Note  Remember that Android will handle focus for you as a matter of routine. This includes jumping between UI elements on the screen and even jumping to the next logical UI element if a UI element (a View object) is hidden (or shown) or removed (or added) as a matter of the application programming logic.

Setting Focus Availability

View objects can be defined (in XML or Java) to be able to accept (or deny) focus using the isFocusable() method or the android:focusable (XML) attribute. If you define a View (UI object) to be focusable (or not focusable) in XML, and then want to change this later at runtime (while your application is running), there is also a setFocusable() method that can flip this (Boolean) switch. To switch Focus On .setFocusable(true); and Off would be .setFocusable(false); as you may have suspected. These focus methods control focus navigation via the smartphone, tablet, e-reader or iTV set navigation key hardware.

There are separate methods to control the focus in relation to the touchscreen, and these are named very similarly: isFocusableInTouchMode() and setFocusableInTouchMode(). For XML markup coding, you would use the format android:focusableInTouchMode, similar to nontouch focus.

Finally, if you simply want to ascertain if there has been a change of focus on a UI object, you can use the onFocusChanged() method. This method can be called to find out if there is a change in state from true to false, or focused to not focused, that you can use in more advanced programming endeavors that watch focus even more closely. With this method, your software can essentially watch what the user is doing with your UI and respond accordingly when the user is “on” each user interface element using onFocusChanged(true). As you can see, Android gives us a huge dose of control over our application’s focus.

Summary

This chapter has covered some very important and advanced concepts in Java programming, as well as in Android app development. The topics ranged from setting up event listeners and event handlers to invoking context-sensitive menus to more ethereal topics such as controlling the focus of your UI design as the user moves through it, all of which represent  important parts of your user experience design—interactivity, predictability, and responsiveness.

You now know how to handle clicks via hardware navigation keys or via the touchscreen, as well as handling long-clicks and keyboard use. We even covered more advanced features such as context menus, the Toast system widget for brief user message notifications, and controlling the focus in your XML or Java code, or via both.

You coded an app that used all the primary event handlers in Android all in one codebase (well over a hundred lines of XML and Java code was written—congratulations on coding your first major project) with no errors, warnings, or crashes. You also learned about the Eclipse Project image Clean … utility; this can help “Clean” or regenerate generated Java files in the project’s /gen/ folder as a way of “cleaning” (debugging) your code when there are no apparent logic or variable errors visible.

We covered a lot of important material in this chapter, so be sure to review it all again very soon. This chapter includes some clever and new ways to use the Eclipse IDE as well, and that is also important to master by the time you are finished with this book, so make sure to play around with the different “panes” in Eclipse such as the Properties, Overview, LogCat, and the Graphical Layout Editor. You should be exploring Eclipse (your IDE tool) as much as you are exploring the Java Classes, XML Tags, Android Libraries, and Method Functions.

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

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