From http://tseng-blog.nge-web.net/blog/2009/02/14/implementing-listeners-in-your-android-java-application/
I don't like inline listeners, and only Android 2 and up support Android:onClick in layout XML,
I have to programming under 1.5, this article is very helpful!
I’ve seen many people asking how to implement Listeners in their
applications. Implementing a Listener is quite easy. There are 3 ways to
implement an Listener and the have their advantages and disadvantages.
The tree way to implement Listeners are
- Inline Implementation
- Using the
implements keyword - By using variables
We’ll use our good old LoginExample application, created in previous
tutorial which can be found at Android:
Your first Android Application.
Inline Implementation
The first way, to implement an listener is by using Inline
Implementation. In Inline Implementations we create an anonymous
listener, define and pass it the the setLisener functions in the same
step.
We did this already in our First
Android Application Tutorial.
01 | package com.tseng.examples; |
05 | public class
LoginExample extends
Activity { |
06 | /** Called when the activity is first created. */ |
08 | public void onCreate(Bundle savedInstanceState) { |
09 | super.onCreate(savedInstanceState); |
14 | btnLogin.setOnClickListener(new OnClickListener()
{ |
16 | public void
onClick(View v) { |
18 | String username = etUsername.getText().toString(); |
19 | String password = etPassword.getText().toString(); |
21 | if(username.equals("guest") && password.equals("guest")){ |
22 | lblResult.setText("Login
successful."); |
24 | lblResult.setText("Login
failed. Username and/or password doesn't match."); |
28 | btnCancel.setOnClickListener(new OnClickListener()
{ |
30 | public void
onClick(View v) { |
As we see, we create an anonymous class there by adding { …
code … } behind the new OnClickListener interface and
implementing the necessary onClick(View v) method.
Advantages
- Small and tidy
- Easy to implement
- Less overhead
Disadvantages
- Inflexible
- Can’t be reused
- Can be a bit harder to maintain
Usage
Inline implementations are usually used for short 1-time methods, for
example if you have a button which closes the application or which
displays, you don’t need to add an implementation to your class or
create a variable, making your code less readable.
Using the “implements” keyword
The second method to implement an Listener is by adding an interface
to your base class. In java you can do this by adding “implements
Interfacename” to the class declaration.
01 | package com.tseng.examples; |
05 | public class
LoginExampleImplements extends Activity implements OnClickListener
{ |
07 | /** Called when the activity is first created. */ |
09 | public void onCreate(Bundle savedInstanceState) { |
10 | super.onCreate(savedInstanceState); |
15 | btnLogin.setOnClickListener(this); |
16 | btnCancel.setOnClickListener(this); |
20 | public void onClick(View v) { |
23 | String username = etUsername.getText().toString(); |
24 | String password = etPassword.getText().toString(); |
26 | if(username.equals("guest") && password.equals("guest")){ |
27 | lblResult.setText("Login
successful."); |
29 | lblResult.setText("Login
failed. Username and/or password doesn't match."); |
31 | } else if(v==btnCancel) { |
As we can see, the “onClick(View v)” is being declared
inside our LoginExample class and additionally we set the
listener by passing a reference to our class to by using btnLogin.setOnClickListener(this);.
This works, because we implemented this interface within our class
public class LoginExampleImplements extends Activity implements
OnClickListener. You may also have noticed, that we add the same
listener to both buttons. Because both of the buttons use the same
listener, we need to differentiate which one was clicked. This can be
done by comparing the View v reference with the Button
btnLogin reference as seen below:
4 | } else if(v==btnCancel) { |
Advantages
- Methods/Listener can be reused in many different widgets
- Code of multiple Listeners is located in the same section of code
- Can be used to create one method for similar Listeners
Disadvantages
- Can contain much unnecessary and untidily code, if the actions
executed are to different and you have to add an
if / elseif /
else blocks, making the code hard to read - You can only have one implementation of this Listener per class
Usage
This method is best used, when you have multiple widgets/elements
using same or similar listeners (i.E. doing a calculation or check on a
click or key press). The example above is not the best example on the
usage of the implement method. Let’s imagine, you have a calculator and
have 14 buttons and you want to update the formula you entered after
every calculator button is pressed, you could implement it in the
following way shown below.
01 | package com.tseng.examples; |
03 | import android.app.Activity; |
04 | import android.os.Bundle; |
05 | import android.view.View; |
06 | import android.view.View.OnClickListener; |
07 | import android.view.View.OnKeyListener; |
08 | import android.widget.Button; |
09 | import android.widget.EditText; |
10 | import android.widget.TextView; |
12 | public class
CalculatorExample extends Activity implements OnClickListener
{ |
16 | public void onClick(View v) { |
19 | String formula = etFormula.getText().toString(); |
20 | Double result = performCalculation(formula); |
23 | tvResult.setText(Strint.valueOf(result)); |
30 | Button button = (Button)v; |
33 | String strToAppend = button.getText().toString(); |
36 | etFormula.append(strToAppend); |
You could add this Listener to every of the calculators button and
only need to define one Listener. When the buttons are clicked, the
button text (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +, –, /, * etc.) will be
added to the TextView containing the formula. However, if you press the
calculate button, it won’t add a = to the formula, but will
instead perform the calculation.
Another very good
implementation of this is, if you want to validate the input in a
TextField altough there are other way in Android by using the
TextView.setFilters(…) Method, but this is another topic.
This is best used when you’re creating your own widgets and want to
to handle clicks (assuming there are only few clickable elements there)
By using Variables
This one is very similar to the previous one, with the difference
that you don’t add the implementation to your class, but instead hold a
reference to the Listener in a variable.
In our LoginExample it would look like this
01 | package com.tseng.examples; |
05 | public class
LoginExampleVariableImplementation extends Activity { |
08 | OnClickListener myClickListener = new OnClickListener() { |
10 | public void onClick(View v) { |
13 | String username = etUsername.getText().toString(); |
14 | String password = etPassword.getText().toString(); |
16 | if(username.equals("guest") && password.equals("guest")){ |
17 | lblResult.setText("Login
successful."); |
19 | lblResult.setText("Login
failed. Username and/or password doesn't match."); |
21 | } else if(v==btnCancel) { |
28 | /** Called
when the activity is first created. */ |
30 | public void onCreate(Bundle savedInstanceState) { |
31 | super.onCreate(savedInstanceState); |
36 | btnLogin.setOnClickListener(myClickListener); |
37 | btnCancel.setOnClickListener(myClickListener); |
Basically we create it anonymous Listener with the difference that we
hold a reference to it. This allows us to add this Listener to more
than only one widget. The main difference to the implements
keyword method is, that we can have more than one Listener inside our
class declared and use them more than once.
Advantages
- Can be reused
- You can have more than one Listener of the same kind in your class
- You can keep your listeners organized in one place, making your code
easier to read
Disadvantages
- Too many listeners can make the code rather complicated to read
Usage
This is best to use if you have different Listeners for the same
action i.e. 2 different OnClickListener which do a completely different
task.
Another very important usage for this variant is if you’re
implementing your own Listeners to your widgets, you could have a
variable which can be assigned by the users of your widgets
01 | package com.tseng.examples; |
03 | import android.app.Activity; |
04 | import android.os.Bundle; |
05 | import android.view.View; |
06 | import android.view.View.OnClickListener; |
07 | import android.view.View.OnKeyListener; |
08 | import android.widget.Button; |
09 | import android.widget.EditText; |
10 | import android.widget.TextView; |
12 | public class
MyWidget extends
View { |
15 | OnClickListener myClickListener = null; |
17 | /** Called
when the activity is first created. */ |
19 | public void onCreate(Bundle savedInstanceState) { |
20 | super.onCreate(savedInstanceState); |
26 | public void setOnClickListener(OnClickListener
listener) { |
27 | myClickListener = listener; |
30 | private onClick(View v) { |
32 | if(myClickListener!=null) |
33 | myClickListener.onClick(v); |
35 | private void handleEventsMethod()
{ |
This allows us to dynamically set the Listener to our widget without
knowing what the listener will actually do with the click, as it can be
implemented in any way the user or programmer wants it to be.
Summary
So there are no “right” ways to implement a Listener. It all depends
on the situation and/or your personal preferences.
| Method
|
Recommended usage
|
| Inline |
Best to use for short and one time only listeners, like
closing an application or displaying an message or call another
Activity/Dialog |
implements-keyword |
If you have only one listener in your class (i.e. your
own widget) or the listeners shares a fairly similar code/task, like the
Calculator Example above |
| Variables |
If you have many Listeners with very different
codebases and tasks or creating your own widget and want to allow your
users to handle the events (i.e. click or key press events). |