An event listener is an object that contains a callback method. This method is called by Android when its trigger is fired by the user interacting with the associated UI item. Simply put, listeners are handlers that "listen" for events in the user interface like clicks or keypresses and respond to them by calling the code written in the body of the method. In this topic, you will learn about several different types of event listeners, each designed to react to a particular event.
Click and LongClick listeners
The first, and probably most important listener, is the OnClickListener. It's called when the user clicks on an interface element or selects it by using the trackball and pressing the Enter button. The below code will close an application when the relevant button is pressed:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.exit).setOnClickListener {
finishActivity()
}
Next is the OnLongClickListener, which is called when the user holds their finger on the element or presses the Enter button. When writing code, you need to consider one important nuance — this listener requires either true or false to be returned. Return true if you only want OnLongClick to react to this event. If you return false, then both OnClick and OnLongClick will be triggered by the event. Here is some example code that will display simple text on the screen when a button is long-pressed:
findViewById<Button>(R.id.toaster).setOnLongClickListener {
Toast.makeText(this, "Long click detected", Toast.LENGTH_SHORT).show()
true
} Keyboard input
Let's start with TextWatcher: this interface is intended to observe the contents of an EditText component.
It has three callback methods:
beforeTextChangedis called first and provides details about the text that's about to change.onTextChangedis called once the change has happened. It gives information about what has been altered.afterTextChangedis called last and provides you with the option to change the text.
The below example shows a Toast message with "before" and "after" text every time input, deletion, cut, or paste operations occur:
findViewById<EditText>(R.id.input).addTextChangedListener(object : TextWatcher {
var old = ""
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
old = s.toString()
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
val new = s.toString()
Toast.makeText(this@MainActivity, "$old -> $new", Toast.LENGTH_SHORT).show()
}
})
You can implement a single TextWatcher method as well. This is done by passing a lambda to AndroidX extension functions:
findViewById<EditText>(R.id.input).doAfterTextChanged { text ->
}
There's also OnKeyListener which is called if the relevant interface element is currently in focus and a phone keyboard button such as Home is pressed. When using it, you again need to return true or false and check which kind of event occurred (the button was pressed, the button was released, and so on).
In the example below, when the Back button is pressed while in the text input field, the user is prompted to press the key twice:
findViewById<EditText>(R.id.title).setOnKeyListener { v, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_BACK &&
event.action == KeyEvent.ACTION_DOWN) {
Toast.makeText(this, "Press twice to go back", Toast.LENGTH_SHORT).show()
true
} else false
}
Using the Back button when the application consists of a single activity is effectively the same as closing it completely. In this situation, you can display a dialog box asking, "Are you sure you want to exit the app?". To implement this, you need to override the behavior of the Back button through the Activity's onBackPressed() function in the following way:
override fun onBackPressed() {
AlertDialog.Builder(this).apply {
setTitle("Confirmation")
setMessage("Are you sure you want to exit the app?")
setPositiveButton("Yes") { _, _ ->
// if user press yes, then exit from app
super.onBackPressed()
}
setNegativeButton("No") { _, _ ->
// if user press no, then return the activity
Toast.makeText(
this@ImageActivity, "Thank you",
Toast.LENGTH_LONG
).show()
}
}.show()
}
Other event listeners
There are many more event listeners, and we will look at a couple of other examples in this section.
The OnFocusChangeListener is called when the View gains or loses focus.
Here's an example:
findViewById<EditText>(R.id.login).setOnFocusChangeListener { _, hasFocus ->
Toast.makeText(this, "Enter a login", Toast.LENGTH_SHORT).show()
}
This code displays a message indicating the EditText that includes the listener is intended for entering a login.
Lastly, the OnCreateContextMenuListener is used to create a long-press context menu. In the example below, when you long-press on an element with text, a context menu that contains Call and SMS options is called up. To use it, you need to override the OnCreateContextMenu method that describes the created context menu and then catch its creation with the listener:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val txtView: TextView = findViewById(R.id.title)
txtView.text = "202-555-0138"
txtView.setOnCreateContextMenuListener(this)
}
override fun onCreateContextMenu(
menu: ContextMenu,
v: View,
menuInfo: ContextMenuInfo?
) {
menu.setHeaderTitle("Select The Action")
menu.add("Call")
menu.add("SMS")
}Conclusion
Event listeners enable your applications to respond to UI events in the ways that you define. You have seen how they can be used to react to events such as clicks, button presses, and changes in focus. There is a wide range of event listeners, so you should be able to find one suitable for most purposes. Don't be shy about looking for those you require via autocomplete, the official documentation, or in the source code!