Event listeners

An event listener is a procedure in an application program that waits for a UI event to occur. There are many types of events that can be emitted within an application. Some common events are click events, touch events, long click events, and text change events.

In order to capture a widget event and perform an action upon its occurrence, a listener for the event must be set to the view. This can be achieved by invoking a view's set. Listener() method and passing either a lambda or a reference to a function to the method invocation.

The following example demonstrates the capturing of a click event done on a button. A lambda is passed to the setOnClickListener method of the view class:

val button: Button = findViewById<Button>(R.id.btn_send)
button.setOnClickListener {
// actions to perform on click event
}

A reference to a function can be passed in place of a lambda:

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val btnExit: Button = findViewById<Button>(R.id.btn_exit)
btnExit.setOnClickListener(this::handleExitEvent)
}
fun handleExitEvent(view: View) {
finish()
}
}

Many listener setter methods are available in the view class. Some examples are:

  • setOnClickListener(): Sets a function to be invoked upon the click of a view
  • setOnContextClickListener(): Sets a function to be invoked upon the context click of a view
  • setOnCreateContextMenuListener(): Sets a function to be invoked upon the creation of a view's context menu
  • setOnDragListener(): Sets a function to be invoked on the occurrence of a drag event on a view
  • setOnFocusChangeListener(): Sets a function to be called on the focus change of a view
  • setOnHoverChangeListener(): Sets a function to be called when a hover event occurs on a view
  • setOnLongClickListener(): Sets a function to be invoked on the occurrence of a long click event on a view
  • setOnScrollChangeListener(): Sets a function to be invoked when the scroll positions (X or Y) of a view change
An event listener is a procedure in an application program that waits for a UI event to occur.

As we now have a good understanding of how to handle input events, we can go on to implement some logic in our MainActivity.

The main activity screen contains an app bar. We need to hide this layout element as our view does not require it:

Appbar

An app bar is also referred to as an action bar. Action bars are instances of the ActionBar class. The instance of the action bar widget in a layout can be retrieved via the supportActionBar accessor variable. The following code retrieves the action bar, and hides it if a null reference is not returned:

package com.mydomain.tetris
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.app.ActionBar
import android.view.View
import android.widget.Button

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val appBar: ActionBar? = supportActionBar

if (appBar != null) {
appBar.hide()
}
}
}

Though the preceding code performs what is necessary, its length can be reduced considerably by exploiting Kotlin's type-safe system, which is as follows:

package com.mydomain.tetris
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
}
}

If supportActionBar is not a null object reference, the hide() method will be invoked if nothing else happens. This will prevent the raising of a null pointer exception.

We need to create object references for the widgets that exist in our layouts. This is necessary for many reasons, such as listener registration. Object references of a view can be retrieved by passing the resource ID of the view to findViewById(). We add object references to MainActivity (existing in the MainActivity.kt file) in the following code snippet:

package com.mydomain.tetris
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView

class MainActivity : AppCompatActivity() {

var tvHighScore: TextView? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()

val btnNewGame = findViewById<Button>(R.id.btn_new_game)
val btnResetScore = findViewById<Button>(R.id.btn_reset_score)
val btnExit = findViewById<Button>(R.id.btn_exit)
tvHighScore = findViewById<TextView>(R.id.tv_high_score)
}
}

Now that we have object references to our user interface elements in place, we need to handle some of their events. We must set click listeners for all buttons in the layout (there's no point having a button that does nothing when clicked, after all).

As we stated earlier on, the New Game button has the sole task of navigating the user to the game activity (where game play takes place). In order to do this, we will need to utilize an explicit intent. Add a private function containing the logic to be executed on the click of the New Game button to MainActivity (in the MainActivity.kt file) and set a reference to the function via setOnClickListener() invocation:

package com.mydomain.tetris
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView

class MainActivity : AppCompatActivity() {

var tvHighScore: TextView? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
val btnNewGame = findViewById<Button>(R.id.btn_new_game)
val btnResetScore = findViewById<Button>(R.id.btn_reset_score)
val btnExit = findViewById<Button>(R.id.btn_exit)
tvHighScore = findViewById<TextView>(R.id.tv_high_score)

btnNewGame.setOnClickListener(this::onBtnNewGameClick)
}

private fun onBtnNewGameClick(view: View) { }
}

Create a new empty activity and name it GameActivity. Once the activity is created, we can utilize an intent to launch the activity on the click of the New Game button, as shown in the following code:

private fun onBtnNewGameClick(view: View) {
val intent = Intent(this, GameActivity::class.java)
startActivity(intent)
}

The first line of the function body creates a new instance of the Intent class and passes the current context and the required activity class to the constructor. Notice we passed this as the first argument to the constructor. The this keyword is used to refer to the current instance in which this is called. Hence, we are actually passing the current activity (MainActivity) as the first argument to the constructor.  At this point, you might be asking why we are passing an activity as the first argument of the Intent constructor when it requires a context as its first argument. This is because all activities are extensions of the Context abstract class. Hence, all activities are in their own rights contexts.

The startActivity() method is called to launch an activity from which no result is expected. When an intent is passed as its only argument, it starts an activity from which it expects no result. Go ahead and run the application to observe the effect of the button click.

Context is an abstract class in the Android application framework. The implementation of a context is provided by the Android system. Context allows access to application-specific resources. Context also allows access to calls for application-level operations such as launching activities, sending broadcasts, and receiving intents.

Now let's implement the following functions for the clicks of the EXIT and RESET SCORE buttons:

package com.mydomain.tetris
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView

class MainActivity : AppCompatActivity() {

var tvHighScore: TextView? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()

val btnNewGame = findViewById<Button>(R.id.btn_new_game)
val btnResetScore = findViewById<Button>(R.id.btn_reset_score)
val btnExit = findViewById<Button>(R.id.btn_exit)
tvHighScore = findViewById<TextView>(R.id.tv_high_score)
btnNewGame.setOnClickListener(this::onBtnNewGameClick)
btnResetScore.setOnClickListener(this::onBtnResetScoreClick)
btnExit.setOnClickListener(this::onBtnExitClick)
}

private fun onBtnNewGameClick(view: View) {
val intent = Intent(this, GameActivity::class.java)
startActivity(intent)
}

private fun onBtnResetScoreClick(view: View) {}

private fun onBtnExitClick(view: View) {
System.exit(0)
}
}

The call to System.exit() in the onBtnExitClick function stops further execution of the program and exits it when the 0 integer is passed as its argument. The last thing we need to do concerning handling click events is to implement the logic to perform the reset of high scores. To do this, we need to implement some logic for data storage first to store the high score. We will do this using SharedPreferences.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.97.75