Tseng’s dev blog

A developers blog



How to implement your own Listener in Android/Java

When you’re developing application, there is often a need to create your own controls/widgets/classes or to extend already available ones. And in most cases, you want this control/widget to be as flexible as possible. In order to achieve this, you have to create special events, which can be handled outside of your widget. Some of the popular examples are OnClickListener and OnKeyListener. But sometimes you need Events/Listener which aren’t predefined by the Java or Android SDK. In this case, you have to create your own Listener interface. In the last post, I’ve shown three different way on how to implement Listeners in your application. Now I’ll show you how to implement your own Listeners.
To demonstrate this, we’ll use our LoginExample activity and modify it slightly to act as a RegisterExample, where you can enter a username + password to create an account. Our goal is to create an application which will allow user to register/create a new account and while the user type his name in the user field, to check “live” if the username is already in use or not. After creating a new project, we’ll copy the main.xml and LoginExample.java file into their respective directories. The LoginExample.java will be renamed RegisterExample.java. First, we do some changes to the main.xml, in order to add a second password field and an TextView, which show us if the username is available or not, as well as changing some labels/texts. The final XML can be seen below
<?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:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Please enter your desired username"
	    />
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Login:"
	    />
	<EditText
		android:id="@+id/username"
		android:singleLine="true"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<TextView
		android:id="@+id/userstatus"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    />
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Password:"
	    />
	<EditText
		android:id="@+id/password"
		android:password="true"
		android:singleLine="true"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Repeat your password:"
	    />
	<EditText
		android:id="@+id/password2"
		android:password="true"
		android:singleLine="true"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<Button
		android:id="@+id/register_button"
		android:text="Register"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<Button
		android:id="@+id/cancel_button"
		android:text="Cancel"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<TextView
		android:id="@+id/result"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    />
</LinearLayout>
If you now start the application, it should look like on the picture below. Screen1 Next, we clean up some of the code from LoginExample and remove unnecessary code as well as refactoring some variable names. The final code should look something like
package com.tseng.examples;

import com.tseng.examples.CheckUsernameEditText.OnUsernameAvailableListener;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class RegisterExample extends Activity {
	// Declare our Views, so we can access them later
	private EditText etUsername;
	private EditText etPassword;
	private EditText etPassword2;
	private Button btnRegister;
	private Button btnCancel;
	private TextView lblUserStatus;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set Activity Layout
        setContentView(R.layout.main);

        // Get the EditText and Button References
        etUsername = (EditText)findViewById(R.id.username);
        etPassword = (EditText)findViewById(R.id.password);
        etPassword2 = (EditText)findViewById(R.id.password2);
        btnRegister = (Button)findViewById(R.id.register_button);
        btnCancel = (Button)findViewById(R.id.cancel_button);
        lblUserStatus = (TextView)findViewById(R.id.userstatus);

        // Set Click Listener
        btnRegister.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// create Account
			}
		});
        btnCancel.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// Close the application
				finish();
			}
		});
    }
}
So far, it looks like our LoginExample. Now the real work can begin. Our goal is to extend the EditText widget for user field and our own code to it, which will check if the username is already in use or not. First, we have to create a new class. We’ll call it CheckUsernameEditText. Once you create the application and it’s default supper class constructors, our first step is to create our own interface.
	// Define our custom Listener interface
	public interface OnUsernameAvailableListener {
		public abstract void onAvailableChecked(String username, boolean available);
	}
Our OnUsernameAvailableListener interface is quite simple and only has defined one abstract method. This method will be called, every time the username was checked and notify the user of the widget if the name was available or not. Now that we have defined the interface, we have to create a variable which will hold the listener by adding this line to top of our CheckUsernameEditText class.
	OnUsernameAvailableListener onUsernameAvailableListener = null;
Next one, we a setter to allow others to listen to this event.
	// Allows the user to set an Listener and react to the event
	public void setOnUsernameAvailableListener(OnUsernameAvailableListener listener) {
		onUsernameAvailableListener = listener;
	}
And last step is to add a small function which we will call every time to trigger the event (and we don’t have to repeat the checking code inside it every time)
	// This function is called after the check was complete
	private void OnUserChecked(String username, boolean available){
		// Check if the Listener was set, otherwise we'll get an Exception when we try to call it
		if(onUsernameAvailableListener!=null) {
			// Only trigger the event, when we have a username
			if(!TextUtils.isEmpty(username)){
				onUsernameAvailableListener.onAvailableChecked(username, available);
			}
		}
	}
So, that was the most important code in creating your own listeners. When ever you want to trigger this event, simply call OnUserChecked(username, available); Currently however, it’s never called. So we need to listen to user input and check the file. We’ll do this, by implementing the OnKeyListener interface to our CheckUserEditText class by changing the class definition to
public class CheckUsernameEditText extends EditText implements OnKeyListener {
Next we have to implement the onKey method, which will be called every time the user presses a key.
	@Override
	public boolean onKey(View v, int keycode, KeyEvent keyevent) {
		// We only want to handle ACTION_UP events, when user releases a key
		if(keyevent.getAction()==KeyEvent.ACTION_DOWN)
			return false;

		boolean available = true;

		// Whenever a user press a key, check if the username is available
		String username = getText().toString().toLowerCase();
		if(!TextUtils.isEmpty(username)){
			// Only perform check, if we have anything inside the EditText box
			for(int i=0; i<registeredUsers.length; i++) {
				if(registeredUsers[i].equals(username)){
					available = false;
					// Finish the loop, as the name is already taken
					break;
				}
			}
			// Trigger the Event and notify the user of our widget
			OnUserChecked(username, available);
			return false;
		}
		return false;
	}
This will check the entered text if the entered username is already available inside our registeredUsers array and set the available variables value to false if the name is already registered, otherwise leave it at it’s standard value of true. Lastly it will call OnUserChecked method, passing by username and it’s status to the listening function.
This will cause an error, because we haven’t defined registeredUsers yet. registeredUsers in our example is a simple String[] array, which will contain a few already registered names.
	final private static String[] registeredUsers = new String[] {
		// This is just a fixed List for tutorial purposes
		// in a real application you'd check this server sided or inside the database
		"tseng",
		"admin",
		"root",
		"joedoe",
		"john"
	};
In your real application you want to get this data from a remote server, an preferences file or from an sqlite database
Our application doesn’t receive any onKey events yet, because we haven’t registered the listener with the TextView’s onKeyListener. So we have to add this line in every of the 3 super class constructors
 //Set KeyListener to ourself
this.setOnKeyListener(this);
Now our CheckUsernameEditText widget is done. How ever, if we start the application we won’t notice a difference, because we haven’t replaced the username’s EditText widget with our own one. We need to change line 17 of our main.xml into
	<com.tseng.examples.CheckUsernameEditText
as well as change RegisterExample.java
	private EditText etUsername;
	// change into
	private CheckUsernameEditText etUsername;
and
        etUsername = (EditText)findViewById(R.id.username);
	// change into
        etUsername = (CheckUsernameEditText)findViewById(R.id.username);
last but not least, we have to set and define the listener to our new CheckUsernameEditText widget.
        // Set our new Listener to the Username EditText view
        etUsername.setOnUsernameAvailableListener(new OnUsernameAvailableListener(){
			@Override
			public void onAvailableChecked(String username, boolean available) {
				// Handle the event here
				if(!available){
					etUsername.setTextColor(Color.RED);
					lblUserStatus.setText(username + " is already taken. Please choose another login name.");
				} else {
					etUsername.setTextColor(Color.GREEN);
					lblUserStatus.setText(username + " is available.");
				}
			}
        });
The onAvailableChecked will be called every time after the check was done. We can put our code here to handle the outcome. The above’s example is pretty easy and will just change the text color of the CheckUsernameTextEdit field and update the lblUserStatus label wo notify the user his desired name is available or not. That’s all. Congratulation to your first own listener implementation. Now we can run our application. If everything worked well, it should look like the screen shots below. Screen2 Screen5 Screen3 Screen4 As always, there is the full source of the files (click on expand to make it visible)

Main.xml

<?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:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Please enter your desired username"
	    />
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Login:"
	    />
	<com.tseng.examples.CheckUsernameEditText
		android:id="@+id/username"
		android:singleLine="true"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<TextView
		android:id="@+id/userstatus"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    />
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Password:"
	    />
	<EditText
		android:id="@+id/password"
		android:password="true"
		android:singleLine="true"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Repeat your password:"
	    />
	<EditText
		android:id="@+id/password2"
		android:password="true"
		android:singleLine="true"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<Button
		android:id="@+id/register_button"
		android:text="Register"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<Button
		android:id="@+id/cancel_button"
		android:text="Cancel"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	/>
	<TextView
		android:id="@+id/result"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    />
</LinearLayout>

CheckUsernameEditText.java

package com.tseng.examples;

import com.tseng.examples.CheckUsernameEditText.OnUsernameAvailableListener;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class RegisterExample extends Activity {
	// Declare our Views, so we can access them later
	private CheckUsernameEditText etUsername;
	private EditText etPassword;
	private EditText etPassword2;
	private Button btnRegister;
	private Button btnCancel;
	private TextView lblUserStatus;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set Activity Layout
        setContentView(R.layout.main);

        // Get the EditText and Button References
        etUsername = (CheckUsernameEditText)findViewById(R.id.username);
        etPassword = (EditText)findViewById(R.id.password);
        etPassword2 = (EditText)findViewById(R.id.password2);
        btnRegister = (Button)findViewById(R.id.register_button);
        btnCancel = (Button)findViewById(R.id.cancel_button);
        lblUserStatus = (TextView)findViewById(R.id.userstatus);

        // Set our new Listener to the Username EditText view
        etUsername.setOnUsernameAvailableListener(new OnUsernameAvailableListener(){
			@Override
			public void onAvailableChecked(String username, boolean available) {
				// Handle the event here
				if(!available){
					etUsername.setTextColor(Color.RED);
					lblUserStatus.setText(username + " is already taken. Please choose another login name.");
				} else {
					etUsername.setTextColor(Color.GREEN);
					lblUserStatus.setText(username + " is available.");
				}
			}
        });

        // Set Click Listener
        btnRegister.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// create Account
			}
		});
        btnCancel.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// Close the application
				finish();
			}
		});
    }
}

RegisterExample.java

package com.tseng.examples;

import java.lang.reflect.Array;

import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.TextView;

public class CheckUsernameEditText extends EditText implements OnKeyListener {
	OnUsernameAvailableListener onUsernameAvailableListener = null;
	final private static String[] registeredUsers = new String[] {
		// This is just a fixed List for tutorial purposes
		// in a real application you'd check this server sided or inside the database
		"tseng",
		"admin",
		"root",
		"joedoe",
		"john"
	};

	public CheckUsernameEditText(Context context) {
		super(context);
		// Set KeyListener to ourself
		this.setOnKeyListener(this);
	}
	public CheckUsernameEditText(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// Set KeyListener to ourself
		this.setOnKeyListener(this);
	}
	public CheckUsernameEditText(Context context, AttributeSet attrs) {
		super(context, attrs);
		// Set KeyListener to ourself
		this.setOnKeyListener(this);
	}

	// Allows the user to set an Listener and react to the event
	public void setOnUsernameAvailableListener(OnUsernameAvailableListener listener) {
		onUsernameAvailableListener = listener;
	}
	// This function is called after the check was complete
	private void OnUserChecked(String username, boolean available){
		// Check if the Listener was set, otherwise we'll get an Exception when we try to call it
		if(onUsernameAvailableListener!=null) {
			// Only trigger the event, when we have a username
			if(!TextUtils.isEmpty(username)){
				onUsernameAvailableListener.onAvailableChecked(username, available);
			}
		}
	}
	@Override
	public boolean onKey(View v, int keycode, KeyEvent keyevent) {
		// We only want to handle ACTION_UP events, when user releases a key
		if(keyevent.getAction()==KeyEvent.ACTION_DOWN)
			return false;

		boolean available = true;

		// Whenever a user press a key, check if the username is available
		String username = getText().toString().toLowerCase();
		if(!TextUtils.isEmpty(username)){
			// Only perform check, if we have anything inside the EditText box
			for(int i=0; i<registeredUsers.length; i++) {
				if(registeredUsers[i].equals(username)){
					available = false;
					// Finish the loop, as the name is already taken
					break;
				}
			}
			// Trigger the Event and notify the user of our widget
			OnUserChecked(username, available);
			return false;
		}
		return false;
	}
	// Define our custom Listener interface
	public interface OnUsernameAvailableListener {
		public abstract void onAvailableChecked(String username, boolean available);
	}
}
That’s all. I hope you enjoyed it. If you have any questions, post it in the comments.

No related posts.







19 Responses to 'How to implement your own Listener in Android/Java'

  1. Patrik - January 3rd, 2010 at 21:51

    Could’nt you please provide the source code? I’m trying to create my own Listener for an TextEdit widget myself, but can’t get it to work. I think the full source can help me.

    Thanks

  2. Wojtek - April 18th, 2010 at 18:14

    nice post, thanks :)

  3. Tweets that mention How to implement your own Listener in Android/Java | Tseng's dev blog -- Topsy.com - April 29th, 2010 at 06:48

    [...] This post was mentioned on Twitter by Shoaib Shaikh. Shoaib Shaikh said: your very own listeners [Droid] http://tseng-blog.nge-web.net/blog/2009/02/17/how-implement-your-own-listener-android-java/ [...]

  4. Samuel - September 16th, 2010 at 02:15

    Thanks, this helped me a lot :)

  5. Zak Guler - January 1st, 2011 at 23:16

    I am new to mobile development and have enjoyed going over how to implement listeners but when I tried implementing how to create my own listener, somehow the code did not work. can you please post the whole source code to see where I went wrong.
    thanx,
    -Zak

  6. Hagai - January 2nd, 2011 at 14:11

    This tutorial is great for understanding how a listener works. The problem is that this method is not actually usable in real life apps as it opens listeners on the main thread of their containing class. Doing so defeats the purpose of using listeners altogether, as they are almost always used for asynchronous operations callbacks from the class that invokes them.

  7. Cómo implementar nuestros Listener en Android | Sentido Droid - February 14th, 2011 at 11:04

    [...] How to implement your own Listener in Android/Java [...]

  8. Korean Translation - March 27th, 2011 at 07:56

    Benedict, it is a great post thanks for posting it!

  9. bouss - April 1st, 2011 at 17:03

    Thanks for this post, but I m sorry it doesn’t work, I tried it, the process is stopped.
    can you give us more details if possible,
    thank you again

  10. Rob Nugen - May 17th, 2011 at 03:28

    Please note that at the very end of the article, the source code for RegisterExample.java and CheckUsernameEditText.java is reversed.

  11. LukCAD - June 9th, 2011 at 13:03

    Thank you a lot. It is most full information how to create custom listener for Android in custom View i found even before.

  12. voiptrunk - July 31st, 2011 at 22:41

    VoIP trunk to Ukraine mobile operator – Voip trunk to Ukraine mobile operator http://voiptrunk.at.ua/

  13. Ranjith - August 10th, 2011 at 06:48

    Good post.. i need to know about URL listener in android would you help me in this regard

  14. Alleto - October 19th, 2011 at 00:17

    Fastest Free Image Hosting. Porsche Boxter 2023 New Model

  15. Santi - November 7th, 2011 at 21:34

    Nice post, thanks!
    Btw, is there any way to avoid “accidentally” double clicking on btnRegister, for example?
    I mean, if i click too fast on that screen button, the program fires twice the action defined in the onClick().
    Thanks in advance!

  16. fatal - January 7th, 2012 at 22:33

    Thanks! Extremely useful!

  17. Mahendran - January 19th, 2012 at 11:12

    FYI..
    The titles of
    RegisterExample.java
    CheckUsernameEditText.java

    switched . though not a problem just informing u. Nice post.. :)

  18. asaf - March 11th, 2012 at 00:14

    are there any other problems with the source code?(other then the switch )
    i try to do this step by step and all so copy paste
    this not working for me
    useing eclipse
    and i get errors on all the @Override still even after removeing them sens they dont really do any thing
    this not working
    geting :
    fatal exception: main
    03-10 23:13:04.156: E/AndroidRuntime(539): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.tseng.examples/com.tseng.examples.RegisterExampleActivity}: java.lang.ClassNotFoundException: com.tseng.examples.RegisterExampleActivity
    ??

  19. Umesh - April 11th, 2012 at 13:56

    Why do we need so many Constructers for CheckUserNameEditText???


Leave a Reply