Event Handling

Three Methods of Handling Events

In this lesson we examine three different methods of handling Events: implementing onClickListener (Android 1.0), anonymous inner classes (Android 1.0) and XML attributes (Android 1.6).

Well it is time to make our app do something! When the user interacts with the buttons in our app, we need to respond by listening to the onClick user events. This is done using event handlers that intercept the user events generated by clicking on the buttons.  There are two ways to intercept user events in Android 1.0 as described here. In addition, event handlers can be added using XML attributes in Android 1.6+ as described here. We investigate all three methods below. When the user clicks on a button, the text is changed in the appropriate EditText object (see Fig. 1).

Figure 1. Our user interface after clicking on each button and after adding the password attribute to the EditTextPassword view object.

Adding the Password Attribute

In the following examples, I have added the password attribute to the EditTextPassword object.  Now when the user enters a Key, only dots are shown. You should also edit string.xml to empty the password field (or enter a default password).

<EditText android:layout_height="wrap_content"

android:text="@string/password_edit_text"

android:id="@+id/EditTextPassword"

android:layout_width="wrap_content"

android:password="true">

<string name="password_edit_text">""</string>

Method 1: Handling Events by Implementing OnClickListener

Here is our first try at intercepting user events. We extend Activity and implement OnClickListener by providing the required method onClick. Note the need to add two import statements to implement OnClickListener and the need to import the android.widget.EditText.

import android.widget.EditText;

import android.view.View;

import android.view.View.OnClickListener;

This first approach minimizes the creation of objects, but is not completely object oriented as it uses a switch statement in the onClick method to dispatch events. The fact that we used user friendly names for the Buttons and Text objects greatly simplified this coding!

package com.google.sites.site.jalcomputing.android.app;

import android.app.Activity;

import android.os.Bundle;

import android.widget.Button;

import android.widget.EditText;

import android.view.View;

import android.view.View.OnClickListener;

//remember to import android.view.View and android.View.OnClickListener

public class ConfuseText extends Activity implements OnClickListener {

    // declare our variables  

    private Button buttonConfuseText;

    private Button buttonPlainText;

    private EditText editTextConfusedText;

    private EditText editTextPlainText;

   

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        // initialize event listeners

        buttonConfuseText= (Button)findViewById(R.id.ButtonConfuseText);

        buttonConfuseText.setOnClickListener(this);

        buttonPlainText= (Button)findViewById(R.id.ButtonPlainText);

        buttonPlainText.setOnClickListener(this);

        editTextConfusedText= (EditText)findViewById(R.id.EditTextConfusedText);

        editTextPlainText= (EditText)findViewById(R.id.EditTextPlainText);

    }

   

    // intercept user interface events here and dispatch them using a switch. Not very object oriented.

    public void onClick(View v){

        switch(v.getId()){

        case R.id.ButtonConfuseText:

            editTextConfusedText.setText("Button Confuse Text Pressed");

            break;

        case R.id.ButtonPlainText:

            editTextPlainText.setText("Button Plain Text Pressed");

            break;

        }   

    }

}

Now when the user clicks on a button, the text in the appropriate view is cleared and a success message is set. The need for a switch statement suggest that this is not a purely object oriented solution.

Method 2. Handling Events Using Anonymous Inner Classes

Here is the second approach to handling events using anonymous inner classes. This approach is more object oriented, but creates more objects and is  more difficult to read.

package com.google.sites.site.jalcomputing.android.app;

import android.app.Activity;

import android.os.Bundle;

import android.widget.Button;

import android.widget.EditText;

import android.view.View;

import android.view.View.OnClickListener;

public class ConfuseText extends Activity{   

    private Button buttonConfuseText;

    private Button buttonPlainText;

    private EditText editTextConfusedText;

    private EditText editTextPlainText;

   

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        // initialize event listeners using anonymous inner classes

        // BUTTON CONFUSE TEXT HANDLER

        buttonConfuseText= (Button)findViewById(R.id.ButtonConfuseText);

        editTextConfusedText= (EditText)findViewById(R.id.EditTextConfusedText);

        buttonConfuseText.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                // TODO Auto-generated method stub

                editTextConfusedText.setText("Confuse Text Button Clicked");

            }

        });

        // BUTTON PLAIN TEXT HANDLER

        buttonPlainText= (Button)findViewById(R.id.ButtonPlainText);

        editTextPlainText= (EditText)findViewById(R.id.EditTextPlainText);

        buttonPlainText.setOnClickListener(new View.OnClickListener() {       

            @Override

            public void onClick(View v) {

                // TODO Auto-generated method stub

                editTextPlainText.setText("Plain Text Button Clicked");

            }

        });

    }

}

Note the use of spacing and ALL CAPS to make the code easier to navigate.

Method 3. Handling Events using XML Attributes

Finally, in Android 1.6 and above, we can set the event handlers in XML. To do this simply add the attribute android:onClick="myOnClickHandler" to each button declaration, where myOnClickHandler is the appropriate event handler in the Java code file. Although this approach is simpler, it does combines event code and presentation code in main.xml, which is antagonistic to the goal of "separation of concerns." For instance, changing the name of the onClick handler in the XML file may cause a run-time error. Here is the main.xml file and simplified java file.

<?xml version="1.0" encoding="utf-8"?>

<ScrollView android:id="@+id/ScrollView01"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

xmlns:android="http://schemas.android.com/apk/res/android">

<TableLayout android:id="@+id/TableLayout01"

android:layout_width="fill_parent"

android:layout_height="fill_parent">

<TableRow>

<EditText android:layout_height="wrap_content"

android:text="@string/password_edit_text"

android:id="@+id/EditTextPassword"

android:layout_width="wrap_content"

android:password="true">

</EditText>

<TextView android:gravity="right"

android:text="@string/password_text_view"

android:id="@+id/TextViewPassword"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</TextView>

</TableRow>

<TableRow>

<EditText android:text="@string/plain_text_edit_text"

android:id="@+id/EditTextPlainText"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</EditText>

<TextView android:text="@string/plain_text_text_view"

android:id="@+id/TextViewPlainText"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</TextView>

</TableRow>

<TableRow>

<TableRow> // embedded Table!

<Button android:text="@string/confuse_text_button"

android:id="@+id/ButtonConfuseText"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick= "confuseTextOnClickHandler">

</Button>

<Button android:text="@string/get_plain_text_button"

android:id="@+id/ButtonPlainText"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick= "plainTextOnClickHandler">

</Button>

</TableRow>

</TableRow>

<TableRow>

<EditText android:text="@string/enter_confused_text_edit_text"

android:id="@+id/EditTextConfusedText"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</EditText>

<TextView android:text="@string/confused_text_text_view"

android:id="@+id/TextViewConfusedText"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</TextView>

</TableRow>

</TableLayout>

</ScrollView>

package com.google.sites.site.jalcomputing.android.app;

import android.app.Activity;

import android.os.Bundle;

import android.widget.EditText;

import android.view.View;

public class ConfuseText extends Activity{ 

    private EditText editTextConfusedText;

    private EditText editTextPlainText;

  

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

      

        editTextConfusedText= (EditText)findViewById(R.id.EditTextConfusedText);

        editTextPlainText= (EditText)findViewById(R.id.EditTextPlainText);  

    }

    public void confuseTextOnClickHandler(View v){

        editTextConfusedText.setText("Confuse Text Button Clicked");

    }

    public voidplainTextOnClickHandler(View v){

        editTextPlainText.setText("Plain Text Button Clicked");

    }

}

All three of theses methods have strengths and weaknesses. I do like the simplicity of the code using XML attributes, but this code is not compatible with Android 1.5, our target minimal API. In order to simplify version issues, we will use anonymous inner classes to handle events in this project.

Have fun,

JAL