Multiple Buttons OnClickListener() - Android

Setting a click listener on one button is easy. Setting it on five buttons without turning your Activity into a wall of anonymous classes — that's where people get stuck. If you've ever written setOnClickListener five times and ended up with five nested blocks of code, this post is for you.

We'll cover four approaches — from the simplest lambda for a single button, to the cleanest pattern for handling many buttons at once — all in Kotlin with ViewBinding. No Java, no deprecated switch statements, no implementing interfaces you don't need.

Multiple buttons OnClickListener Android

Photo by Gal Shir on Dribbble

Approach 1 — Lambda (Best for 1–2 Buttons)

For one or two buttons, a simple lambda is the cleanest approach. No interface, no extra method, just inline code:

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.btnSubmit.setOnClickListener {
            // handle submit click
            showToast("Submit clicked")
        }

        binding.btnCancel.setOnClickListener {
            // handle cancel click
            showToast("Cancel clicked")
        }
    }

    private fun showToast(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
}
💡 ViewBinding tip: Replace findViewById(R.id.btnSubmit) with binding.btnSubmit. It's null-safe, type-safe, and requires zero casting. Enable it in build.gradle with viewBinding { enabled = true }.

Approach 2 — Single Listener with when (Best for 3–6 Buttons)

When you have several buttons doing different things, create one click listener and use Kotlin's when expression to route each button to its action. This is the modern replacement for the old Java switch(v.getId()) pattern:

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Assign the same listener to all buttons
        val clickListener = View.OnClickListener { view -> handleClick(view) }

        binding.btnOne.setOnClickListener(clickListener)
        binding.btnTwo.setOnClickListener(clickListener)
        binding.btnThree.setOnClickListener(clickListener)
        binding.btnFour.setOnClickListener(clickListener)
    }

    private fun handleClick(view: View) {
        when (view.id) {
            R.id.btnOne   -> onButtonOneClicked()
            R.id.btnTwo   -> onButtonTwoClicked()
            R.id.btnThree -> onButtonThreeClicked()
            R.id.btnFour  -> onButtonFourClicked()
        }
    }

    private fun onButtonOneClicked() {
        Toast.makeText(this, "Button One", Toast.LENGTH_SHORT).show()
    }

    private fun onButtonTwoClicked() {
        Toast.makeText(this, "Button Two", Toast.LENGTH_SHORT).show()
    }

    private fun onButtonThreeClicked() {
        // navigate to next screen
        startActivity(Intent(this, SecondActivity::class.java))
    }

    private fun onButtonFourClicked() {
        // do something else
    }
}

Keeping each button's logic in its own private function keeps handleClick() clean and each action independently testable.

Approach 3 — apply Block (Cleanest Setup Code)

If you find the repeated setOnClickListener calls noisy, Kotlin's apply block makes the setup more readable — especially when you're also setting other properties on the buttons:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    setupClickListeners()
}

private fun setupClickListeners() {
    with(binding) {
        btnOne.setOnClickListener   { onButtonOneClicked() }
        btnTwo.setOnClickListener   { onButtonTwoClicked() }
        btnThree.setOnClickListener { onButtonThreeClicked() }
        btnFour.setOnClickListener  { onButtonFourClicked() }
        btnFive.setOnClickListener  { onButtonFiveClicked() }
    }
}

Using with(binding) avoids repeating binding. on every line. All setup is in one method, and onCreate() stays clean.

Approach 4 — Extension Function (Reusable Across the App)

If you frequently set the same click behaviour across multiple screens, an extension function keeps it DRY:

// Create once in a utility file — e.g. ViewExtensions.kt
fun View.onClick(action: () -> Unit) {
    setOnClickListener { action() }
}

// Usage — reads like plain English
binding.btnSubmit.onClick  { submitForm() }
binding.btnCancel.onClick  { cancelAndGoBack() }
binding.btnHelp.onClick    { showHelpDialog() }
binding.btnSettings.onClick { openSettings() }

Handling Multiple Clicks in a Fragment

In Fragments, always set click listeners in onViewCreated() — not onCreateView(). And always use viewLifecycleOwner for anything lifecycle-related:

class HomeFragment : Fragment() {

    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Set all click listeners here — NOT in onCreateView
        with(binding) {
            btnProfile.setOnClickListener  { navigateToProfile() }
            btnSettings.setOnClickListener { navigateToSettings() }
            btnLogout.setOnClickListener   { showLogoutConfirmation() }
            btnHelp.setOnClickListener     { openHelpCenter() }
        }
    }

    private fun navigateToProfile() {
        findNavController().navigate(R.id.action_home_to_profile)
    }

    private fun navigateToSettings() {
        findNavController().navigate(R.id.action_home_to_settings)
    }

    private fun showLogoutConfirmation() {
        // show dialog
    }

    private fun openHelpCenter() {
        // open URL or screen
    }

    // Always null the binding in onDestroyView to prevent memory leaks
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

Bonus - Prevent Double Clicks

A common real-world problem — user taps a button twice quickly and triggers the action twice. A submit button that fires two API calls, a navigation that opens two screens. Here's a clean extension to prevent it:

// Add to ViewExtensions.kt
fun View.setOnSingleClickListener(debounceTime: Long = 600L, action: () -> Unit) {
    var lastClickTime = 0L
    setOnClickListener {
        val now = System.currentTimeMillis()
        if (now - lastClickTime >= debounceTime) {
            lastClickTime = now
            action()
        }
    }
}

// Usage — drop-in replacement for setOnClickListener
binding.btnSubmit.setOnSingleClickListener {
    submitForm() // Only fires once even if tapped multiple times quickly
}

Which Approach Should You Use?

Approach Best For Avoid When
Lambda 1–2 buttons, simple actions 5+ buttons — gets repetitive
when expression 3–6 buttons, all in same class Actions are complex — extract to separate methods
with(binding) Any number, cleanest setup Never — this is always a good pattern
Extension function Shared patterns across the app One-off clicks — overkill for single use

Best Practices

  • Use ViewBinding instead of findViewById — it's null-safe, no casting needed, and catches ID mismatches at compile time instead of runtime. Enable it once in build.gradle and use it everywhere.
  • Keep onClick logic out of the listener — the listener should call a named private method, not contain the logic itself. binding.btnSubmit.setOnClickListener { submitForm() } is far more readable than 10 lines of code inside the lambda.
  • Set listeners in onViewCreated(), not onCreateView() — in Fragments, the view is guaranteed to be non-null in onViewCreated(). Setting listeners in onCreateView() can cause subtle issues.
  • Always null the binding in Fragment's onDestroyView() — binding holds a reference to the view. If you don't null it, the Fragment leaks memory after navigation.
  • Use setOnSingleClickListener for form submissions — any button that triggers a network call, navigation, or database write should be protected against double taps. Users tap faster than you think.

Frequently Asked Questions

How do I set OnClickListener for multiple buttons in Kotlin?
Create one click listener, assign it to all buttons, then use a when expression to route each button by its ID. Or use with(binding) to set individual lambdas cleanly. Both approaches are readable and avoid repetition.

What is the difference between setOnClickListener and OnClickListener?
setOnClickListener is the method you call on a View to attach a handler. OnClickListener is the Java interface with the onClick() method. In Kotlin, pass a lambda to setOnClickListener — you rarely need to implement the interface explicitly.

How do I handle button clicks in a Fragment?
Set listeners in onViewCreated() — not onCreateView(). Use ViewBinding for null-safe view access. Always null the binding in onDestroyView() to prevent memory leaks.

How do I prevent double clicks on a button?
Create a setOnSingleClickListener extension function that tracks the last click timestamp and ignores clicks within 600ms. Use it on any button that triggers a network call, navigation, or database write.

📝 Summary
  • Lambda — best for 1–2 buttons: binding.btn.setOnClickListener { doSomething() }
  • when expression — best for 3–6 buttons sharing one listener
  • with(binding) — cleanest setup for any number of buttons
  • Extension function — reusable patterns across the whole app
  • Always use ViewBinding — no findViewById, no casting, no null crashes
  • Set listeners in onViewCreated() in Fragments — not onCreateView()
  • Null binding in onDestroyView() to prevent Fragment memory leaks
  • Use setOnSingleClickListener on submit buttons to prevent double taps

Pragnesh Ghoda

A forward-thinking developer offering more than 8 years of experience building, integrating, and supporting android applications for mobile and tablet devices on the Android platform. Talks about #kotlin and #android

8 Comments

Please let us know about any concerns or query.

  1. Would u please do one with just two buttons to set on different activites

    ReplyDelete
    Replies
    1. You can use same type of implementation for both activities. Implement `OnClickListener` interface in activity/fragment. Override `onClick()` method, and assign that listener with `setOnClickListener()` method of buttons.

      Delete
  2. what can i do if i want to do same thing with 3 button . this code dose not work for same thing

    ReplyDelete
    Replies
    1. use same method or call for those 3 buttons by passing same case into switch.

      case R.id.buttonOne:
      case R.id.buttonTwo:
      case R.id.buttonThree:
      // code for button when user clicks buttonOne.
      break;

      Delete
  3. I Get java. Lang. Runtime exception

    ReplyDelete
  4. I have an error that says "Constant expression required." What can I do about this?

    ReplyDelete
Previous Post Next Post

Contact Form