Different Ways to Code Android Event Listeners
An Android View
in an application (App) will fire an event in response to user or code interaction. The App will not respond to the event unless it is listening for it. To detect the event a class that implements a listener is instantiated and assigned to the View. This is one of the most common programming patterns in an Android App. This tutorial covers the main ways an event listener is coded in Android. When writing software very rarely is there only one way to do things, this is true when wiring up View events. The different methods a programmer will encounter are discussed in this article. An example project is provided.
(This Android tutorial assumes that Android Studio is installed; a basic App can be created and run; and code can be correctly copied into Studio. Here, for the tutorial App, the Application name is set to Coding Listeners and an Empty Activity is used. Adapt the tutorial code as required.)
The Common onClick Event
The onClick()
event is the most widely used event in Android Apps. Nearly every View that can be added to an App screen will fire the event when the user touches it with their finger (or clicks the trackpad/trackball/mouse when the View has focus on non-touch devices). This event is listened to by a class implementing the OnClickListener
interface. A View is assigned an instance of that class using the View's setOnClickListener()
method. This tutorial shows several ways this can be achieved. There are pros and cons for each method and experienced developers will advocate a particular method over others. But not one of the methods can be regarded as the must do way. Developers need to be familiar with the different ways to code event handlers, they will come across the different methods in tutorials, samples and online snippets.
For the basic starting App in Studio the TextView text size has been set to 20sp and the text changed to Click a button. (Use the Properties pane or edit the XML code.) Drag and drop a button onto the screen (or add it via the XML), set the id to button1 and text to Button 1. The TextView id is textView. The layout file, here activity_main.xml (in the res/layout folder), should be similar to this:
<?xml version="1.0" encoding="utf-8"?>
<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.codinglisteners.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click a button."
android:id="@+id/textView"
android:textSize="20sp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1"
android:id="@+id/button1"
android:layout_below="@+id/textView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
In the following methods for coding a listener the displayed text changes on the button press. For each example shown replace the MainActivity class with the code shown. Studio will prompt to add any missing import statements. The final imports will be:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
Because the App used here is based on the default Studio App the Android Support Library is used. Hence the use of AppCompatActivity
instead of simply Activity
(from which AppCompatActivity is derived).
Member Class Example
A class called HandleClick implementing OnClickListener is declared as a member of MainActivity. This is useful when several listeners require similar processing that can be handled by a single class.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//attach an instance of HandleClick to the Button
findViewById(R.id.button1).setOnClickListener(new HandleClick());
}
private class HandleClick implements View.OnClickListener {
public void onClick(View arg0) {
Button btn = (Button)arg0; //cast view to a button
// update the TextView text
((TextView)findViewById(R.id.textView)).setText("You pressed " + btn.getText());
}
}
}
Interface Type Example
In Java an Interface can be used as a type, a variable is declared as an OnClickListener and assigned using new View.OnClickListener(){...}, behind the scenes Java is creating an object (an Anonymous Class) that implements OnClickListener. This has similar benefits to the first method.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//attach an instance of HandleClick to the Button
findViewById(R.id.button1).setOnClickListener(handleClick);
}
private View.OnClickListener handleClick = new View.OnClickListener(){
public void onClick(View arg0) {
Button btn = (Button)arg0;
TextView tv = (TextView) findViewById(R.id.textView);
tv.setText("You pressed " + btn.getText());
}
};
}
Anonymous Inner Class Example
Declaring the OnClickListener within the call to the setOnClickListener method is common. This method is useful when each listener does not have functionality that could be shared with other listeners. Some novice developers find this type of code difficult to understand. Again behind the scenes for new View.OnClickListener(){...} Java is creating an object that implements the interface.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//attach an instance of HandleClick to the Button
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener(){
public void onClick(View arg0) {
Button btn = (Button)arg0;
TextView tv = (TextView) findViewById(R.id.textView);
tv.setText("You pressed " + btn.getText());
}
});
}
}
Implementation in Activity Example
The Activity (AppCompatActivity) itself can implement the OnClickListener. Since the Activity object (main) already exists this saves a small amount of memory (not requiring another object to host the onClick method). It does make public a method that is unlikely to be used elsewhere. Implementing multiple events will make the declaration of main long.
public class main extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//attach an instance of HandleClick to the Button
findViewById(R.id.button1).setOnClickListener(this);
}
public void onClick(View arg0) {
Button btn = (Button)arg0;
TextView tv = (TextView) findViewById(R.id.textView);
tv.setText("You pressed " + btn.getText());
}
}
Attribute in View Layout for OnClick Events
Since API level 4 (Android 1.6) onwards the name of a method can be assigned to the android:onClick attribute in a layout file. This can save writing some code.
public class MainActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void HandleClick(View arg0) {
Button btn = (Button)arg0;
TextView tv = (TextView) findViewById(R.id.textView);
tv.setText("You pressed " + btn.getText());
}
}
In the layout file the Button would be declared with the android:onClick attribute.
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1"
android:id="@+id/button1"
android:layout_below="@+id/textView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="HandleClick" />
For each button added to the layout file that uses the android:onClick attribute no additional code is required than that defined above, this eliminates multiple findViewById and setOnClickListener code used by the other methods.
Finally
The first four methods of handling events can be used with other event types (onLongClick, onKey, onTouch, onCreateContextMenu, onFocusChange). The final method only applies to the onClick event. Deciding upon which technique to use to wire up a listener will depend on the functionality required, how much code is reusable across Views and how easy the code would be to understand by future maintainers. Ideally the code should be succint and easy to view.
One method not shown here is similar to the first method. The listener class in the first method is saved into a separate class file as a public class. Then instances of that public class could be used by other Activities, passing the Activity's context in via the constructor. However, Activities should try and stay self contained in case they are killed by Android. Sharing listeners across Activities is against the ideals of the Android platform and could lead to unnecessary complexity passing references between the public classes.
Download the code for this article ready for importing into Android Studio. The code can also be accessed via the Android Example Projects page. A version of this article was produced for the Android Cookbook.
Archived Comments
2012/07/05 at 6:15 am - Rupali - Very Useful.
2012/07/18 at 9:50 am - Hessi - Hello, I have 2 classes, first class extends Activity and second class not. In first class there are some views, and I want to access them in second class for handling. I declare them in static type and instantiate in onCreate method but when I want to access them in second class error! I don’t want to change my classes structure, i.e. I don’t want to make that second class extends Activity. How to solve my problem? Plz.
2012/07/18 at 11:27 am - Tek Eye in response to Hessi - Hi, in the constructor for the second class declare that it takes an Activity and pass the reference for the first activity into it when the class is created. For example here is a second class that can take an Activity reference in the constructor and has a method to change some text on a View:
package com.example.helloworld;
import android.app.Activity;
import android.widget.TextView;
public class SecondClass {
Activity activityRef;
public SecondClass(Activity activityReference) {
activityRef = activityReference;
}
public void ChangeTextBox(String newText)
{
TextView localViewRef;
localViewRef = (TextView) activityRef.findViewById(R.id.myTextBox);
localViewRef.setText(newText);
}
}
And here the class is created and the method called to access a TextView in the second class:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
public class HelloWorldActivity extends Activity {
SecondClass otherClass;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
otherClass = new SecondClass(this);
otherClass.ChangeTextBox("New Text");
}
}
Author:Daniel S. Fowler Published: Updated: