Bất kì ứng dụng nào cũng đều phải tương tác với người dùng. Ứng dụng Android cũng vậy. Bài hướng dẫn này sẽ hướng dẫn các phương pháp chính để bắt và xử lý sự kiện – event trong Android.

View trong ứng dụng Android sẽ kích hoạt một sự kiện để phản hồi lại cho người. Để phát hiện sự kiện, một class sẽ implement một listener và truyền cho View. Đây là một trong những mô hình lập trình phổ biến nhất trong ứng dụng Android

Để có thể phát hiện và xử lý một sự kiện từ người dùng, chúng ta có 5 cách:

  • Tạo riêng một member Class
  • Tạo riêng một Interface
  • Sử dụng Anonymous Inner Class
  • Implement Event Listeners trực tiếp từ Activity
  • Cuối cùng là dùng thuộc tính onClick trong layout

Cả 5 cách này về bản chất là đều implement các Event Interface. Tùy vào kiến trúc dự án, thói quen lập trình mà bạn có thể chọn một cách để làm.

Chúng ta bắt đầu nhé!

Đôi điều về xử lý sự kiện trong Android

Trong Android có rất nhiều sự kiện(event) như: onTouch(), onLongClick(), onFocusChange(), onClick()… Nhưng có lẽ onclick( )là sự kiện được dùng nhiều nhất trong ứng dụng Android.

Mỗi View được thêm vào màn hình ứng dụng đều có sẵn các sự kiện khi người dùng chạm vào ( hoặc dùng touchpad/ trackball/ chuột đối với các thiết bị không hỗ trợ cảm ứng). Sự kiện này được lắng nghe bởi class nào đã implement OnClickListener.

Bài viết này mình sẽ tập trung trình bày cách khác nhau để bắt và xử lý sự kiện onClick(). Với các sự kiện khác hoàn toàn tương tự.

Để minh họa cho bài viết, mình sẽ tạo một layout activity_main.xml có TextView và Button như bên dưới:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.codinglisteners.MainActivity">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click a button."
        android:id="@+id/textView"
        android:textSize="20sp" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1"
        android:id="@+id/button1"
        android:layout_below="@+id/textView"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />
</RelativeLayout>

Bài viết này sẽ làm một ví dụ đơn giản để minh họa như sau: Mỗi khi người dùng chạm vào Button thì sẽ thay đổi nội dung cho TextView. Trong MainActivity.kt, bạn sẽ import các thư viện cơ bản sau

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

Protip: Android Studio có thể tự import cho bạn những viện cần thiết bằng cách đưa chuột vào chỗ text nào bị gạch chân màu đỏ rồi nhất Alt+ Enter.

OK, bộ khung đã xong, chúng ta sẽ cùng thử lần lượt các cách phát hiện và xử lý sự kiện onClick() nhé

#1. Tạo riêng Member Class

Chúng ta tạo riêng một class trong Activity và đặt tên là HandleClick. HandleClick sẽ implemetent OnClickListener. Cách này rất hữu ích khi có một vài listener cần xử lý giống nhau

class MainActivity:AppCompatActivity() {
  protected fun onCreate(savedInstanceState:Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    //attach an instance of HandleClick to the Button
    findViewById(R.id.button1).setOnClickListener(HandleClick())
  }
  private inner class HandleClick:View.OnClickListener {
    fun onClick(arg0:View) {
      val btn = arg0 as Button //cast view to a button
      // update the TextView text
      (findViewById(R.id.textView) as TextView).setText("You pressed " + btn.getText())
    }
  }
}

#2. Tạo riêng Interface

Trong Java, một Interface có thể được sử dụng như một type. Chúng ta khai báo một biến kiểu OnClickListener bằng câu lệnh object:View.OnClickListener(){}. Cách làm này cũng gần giống với cách 1 ở trên.

class MainActivity:AppCompatActivity() {
  private val handleClick = object:View.OnClickListener() {
    fun onClick(arg0:View) {
      val btn = arg0 as Button
      val tv = findViewById(R.id.textView) as TextView
      tv.setText("You pressed " + btn.getText())
    }
  }
  protected fun onCreate(savedInstanceState:Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    //attach an instance of HandleClick to the Button
    findViewById(R.id.button1).setOnClickListener(handleClick)
  }
}

#3. Sử dụng Anonymous Inner Class

Cách này đơn giản là chúng ta khởi tạo luôn một instance của OnClickListener trong đối số của của hàm setOnClickListener. Cách này này rất hữu dụng khi bạn muốn viết code nhanh, và phần xử lý sự kiện không tái xử dụng ở đâu trong dự án. Một số bạn chưa có kinh nghiệm có thể thấy code này khó hiểu. Nhưng thực ra, về bản chất cũng giống như các cách khác là đều tạo instance của View.OnClickListener(){…} bằng lệnh object:View.OnClickListener

class MainActivity:AppCompatActivity() {
  protected fun onCreate(savedInstanceState:Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    //attach an instance of HandleClick to the Button
    findViewById(R.id.button1).setOnClickListener(object:View.OnClickListener() {
      fun onClick(arg0:View) {
        val btn = arg0 as Button
        val tv = findViewById(R.id.textView) as TextView
        tv.setText("You pressed " + btn.getText())
      }
    })
  }
}

#4. Implement trực tiếp trên Activity

Activity có thể implement luôn OnClickListener. Với cách này thì Activity sẽ phải override lại hàm onClick(). Nhược điểm của cách này chúng ta không thể tái sử dụng phần xử lý sự kiện onClick()ở class khác.

class main:AppCompatActivity(), View.OnClickListener {
  protected fun onCreate(savedInstanceState:Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    //attach an instance of HandleClick to the Button
    findViewById(R.id.button1).setOnClickListener(this)
  }
  fun onClick(arg0:View) {
    val btn = arg0 as Button
    val tv = findViewById(R.id.textView) as TextView
    tv.setText("You pressed " + btn.getText())
  }
}

#5. Sử dụng thuộc tính onCLick trong View Layout

Từ API level 4 (Android 1.6) trở đi, tên của một hàm có thể được gán cho thuộc tính android:onClick trong một layout.

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button 1"
    android:id="@+id/button1"
    android:layout_below="@+id/textView"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:onClick="handleClick" />

Sau đó thì hàm đó được viết trong Activity như sau

class MainActivity:AppCompatActivity() {
  fun onCreate(savedInstanceState:Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
  }
  fun handleClick(arg0:View) {
    val btn = arg0 as Button
    val tv = findViewById(R.id.textView) as TextView
    tv.setText("You pressed " + btn.getText())
  }
}

Lưu ý: Tham số của hàm được định nghĩa trong thuộc tính của layout luôn là View. Ví dụ trong layout mình đặt tên hàm là handleClick thì trong Activity hàm đó phải là handleClick(View arg)

Với cách này thì code của bạn sẽ khá gọn, không cần phải gọi findViewById()hay setOnClickListener(). Tuy nhiên, người khác đọc code của bạn sẽ khá khó hiểu và rối khi debug

Tổng kết

Bốn phương thức đầu tiên có thể được sử dụng với các loại event khác (onLongClick, onKey, onTouch, onCreateContextMenu, onFocusChange). Phương thức cuối cùng chỉ áp dụng cho sự kiện onClick.

Như vậy, mình đã chia sẻ với các bạn các cách phổ biến nhất để xử lý sự kiện trong Android. Với cá nhân mình, thì cách 4 là hay sử dụng nhất. Các listener nên đóng gói trong Activity và không nên share listener giữa các Activity.

Bài viết tham khao từ vntalking.com

About the author

Kevin Dang

Hey there! My name is Kevin Dang, I am website, software, mobile app develop, web admin system. Expert living in Hồ Chí Minh (Việt Nam). I am very interested in digital marketing with: SEO, Facebook, Google Ads ... This blog is where I will share the experiences, techniques and knowledge I have learned.