Android: OnClickListener Ways
Overview:
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 they will come across the different methods in tutorials, samples and online snippets.
In Event Delegation Model when a View fires an event an Application will not respond to it unless it is listening for it. To detect the event a class that implements a listener is instantiated and assigned to the View.
Take for example the onClick event, 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 stabs it with their finger (on touch screens) or presses the trackpad/trackball when the View has focus. This event is listened to by a class implementing the OnClickListener interface.
The class instance is then assigned to the required View using the View's setOnClickListener method.
There are different ways of handling the Click event in android.
- Member Class
- Interface Type
- Anonymous Inner Class (Inline method)
- Implementation in Activity
- Attribute in View Layout for OnClick Events
1. Member Class
A class called HandleClick implementing OnClickListener is declared as a member of the Activity (MainActivity). This is useful when several listeners require similar processing than can be handled by a single class.
public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //attach an instance of HandleClick to the Button findViewById(R.id.button1).setOnClickListener(new HandleClick()); } private class HandleClick implements OnClickListener{ public void onClick(View arg0) { Button btn = (Button)arg0; //cast view to a button // get a reference to the TextView TextView tv = (TextView) findViewById(R.id.textview1); // update the TextView text tv.setText("You have pressed " + btn.getText()); } } }
2. Interface Type
In Java an Interface can be used as a type, a variable is declared as an OnClickListener and assigned using new 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 Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //use the handleClick variable to attach the event listener findViewById(R.id.button1).setOnClickListener(handleClick); } private OnClickListener handleClick = new OnClickListener(){ public void onClick(View arg0) { Button btn = (Button)arg0; TextView tv = (TextView) findViewById(R.id.textview1); tv.setText("You have pressed " + btn.getText()); } }; }
3. Anonymous Inner Class (Inline method)
public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button1).setOnClickListener(new OnClickListener(){ public void onClick(View arg0) { Button btn = (Button)arg0; TextView tv = (TextView) findViewById(R.id.textview1); tv.setText("You have pressed " + btn.getText()); } }); } }
4. Implementation in Activity
public class MainActivity extends Activity implements OnClickListener{ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button1).setOnClickListener(this); } public void onClick(View arg0) { Button btn = (Button)arg0; TextView tv = (TextView) findViewById(R.id.textview1); tv.setText("You have pressed " + btn.getText()); } }
5. Attribute in View Layout for OnClick Events
public class MainActivity extends Activity{ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void HandleClick(View arg0) { Button btn = (Button)arg0; TextView tv = (TextView) findViewById(R.id.textview1); tv.setText("You have pressed " + btn.getText()); } }
<Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 1" android:onClick="HandleClick"/>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/textview1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Click a button." android:textSize="20dp"/> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 1" android:onClick="HandleClick"/> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 2" android:onClick="HandleClick"/> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 3" android:onClick="HandleClick"/> </LinearLayout> </LinearLayout>
One method not shown here is similar to the first method. In the first method it would be possible to save the listener class in a different 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.