Android: cómo manejar el clic del botón


95

Con una sólida experiencia en el área que no es de Java ni de Android, estoy aprendiendo Android.

Tengo mucha confusión con diferentes áreas, una de ellas es cómo manejar los clics en los botones. Hay al menos 4 formas de hacerlo (!!!), se enumeran brevemente aquí

por motivos de coherencia, los enumeraré:

  1. Tenga un miembro de la View.OnClickListenerclase en la actividad y asígnelo a una instancia que manejará la onClicklógica en el onCreatemétodo de la actividad.

  2. Cree 'onClickListener' en el método de actividad 'onCreate' y asígnelo al botón usando setOnClickListener

  3. Implemente 'onClickListener' en la actividad misma y asigne 'this' como oyente para el botón. En el caso de que la actividad tenga pocos botones, se debe analizar la identificación del botón para ejecutar el controlador 'onClick' para el botón adecuado

  4. Tenga un método público en la actividad que implemente la lógica 'onClick' y asígnelo al botón en la declaración xml de la actividad

Pregunta 1:

¿Son todos esos métodos, hay alguna otra opción? (No necesito otro, solo curiosidad)

Para mí, la forma más intuitiva sería la última: requiere que se escriba la menor cantidad de código y es la más legible (al menos para mí).

Sin embargo, no veo que este enfoque se use ampliamente. ¿Cuáles son las desventajas de usarlo?

Pregunta 2:

¿Cuáles son las ventajas y desventajas de cada uno de estos métodos? Comparta su experiencia o un buen enlace.

¡Cualquier comentario es bienvenido!

PD: He intentado buscar en Google y encontrar algo para este tema, pero las únicas cosas que he encontrado son la descripción "cómo" hacerlo, no por qué es bueno o malo.

Respuestas:


147

Pregunta 1: Lamentablemente el que dices que es más intuitivo es el que menos se usa en Android. Según tengo entendido, debe separar su interfaz de usuario (XML) y la funcionalidad computacional (archivos de clase Java). También facilita la depuración. En realidad, es mucho más fácil leer de esta manera y pensar en Android imo.

Pregunta 2: Creo que los dos que se utilizan principalmente son el 2 y el 3. Usaré un botón clickButton como ejemplo.

2

tiene la forma de una clase anónima.

Button clickButton = (Button) findViewById(R.id.clickButton);
clickButton.setOnClickListener( new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                ***Do what you want with the click here***
            }
        });

Este es mi favorito, ya que tiene el método onClick justo al lado de donde se estableció la variable del botón con findViewById. Parece muy limpio y ordenado que todo lo relacionado con esta vista de botones de clic se encuentre aquí.

Una desventaja que comenta mi compañero de trabajo es que imagina que tienes muchas vistas que necesitan un oyente onclick. Puede ver que su onCreate se alargará mucho. Entonces por eso le gusta usar:

3

Digamos que tiene, 5 clickButtons:

Asegúrese de que su actividad / fragmento implemente OnClickListener

// in OnCreate

Button mClickButton1 = (Button)findViewById(R.id.clickButton1);
mClickButton1.setOnClickListener(this);
Button mClickButton2 = (Button)findViewById(R.id.clickButton2);
mClickButton2.setOnClickListener(this);
Button mClickButton3 = (Button)findViewById(R.id.clickButton3);
mClickButton3.setOnClickListener(this);
Button mClickButton4 = (Button)findViewById(R.id.clickButton4);
mClickButton4.setOnClickListener(this);
Button mClickButton5 = (Button)findViewById(R.id.clickButton5);
mClickButton5.setOnClickListener(this);


// somewhere else in your code

public void onClick(View v) {
    switch (v.getId()) {
        case  R.id.clickButton1: {
            // do something for button 1 click
            break;
        }

        case R.id.clickButton2: {
            // do something for button 2 click
            break;
        }

        //.... etc
    }
}

De esta manera, como explica mi compañero de trabajo, es más ordenado a sus ojos, ya que todo el cálculo de onClick se maneja en un solo lugar y no satura el método onCreate. Pero la desventaja que veo es que:

  1. se ven a sí mismos,
  2. y cualquier otro objeto que pueda estar ubicado en onCreate utilizado por el método onClick deberá convertirse en un campo.

Avísame si quieres más información. No respondí tu pregunta por completo porque es una pregunta bastante larga. Y si encuentro algunos sitios ampliaré mi respuesta, ahora mismo solo estoy dando algo de experiencia.


1
Para la opción 2, querrá hacerlo: clickButton.setOnClickListener (new View.OnClickListener () {@Override public void onClick (View v) {// TODO lo que desea hacer}}); para ayudarlo a resolver OnClickListener
ColossalChris

La opción 3 es probablemente la más limpia y fácil de extender con el patrón MVP.
Raffaeu

La opción 2 aún puede producir onCreate()que no sea demasiado larga. Las asignaciones de escucha de clics y las clases anónimas se pueden factorizar en un método auxiliar separado desde el que se llama onCreate().
Nick Alexeev

@Colossal: No tienes que hacerlo. Agregue extensión a la clase de actividad como "implementa View.OnClickListener".
TomeeNS

10

# 1 Utilizo el último con frecuencia cuando tengo botones en el diseño que no se generan (pero obviamente estáticos).

Si lo usa en la práctica y en una aplicación comercial, preste especial atención aquí, porque cuando usa source ofuscater como ProGuard, deberá marcar estos métodos en su actividad para que no se ofusquen.

Para archivar algún tipo de seguridad en tiempo de compilación con este enfoque, eche un vistazo a Android Lint ( ejemplo ).


# 2 Los pros y los contras de todos los métodos son casi los mismos y la lección debería ser:

Utilice lo que sea más apropiado o que le parezca más intuitivo.

Si tiene que asignar lo mismo OnClickListenera varias instancias de botón, guárdelo en el ámbito de clase (# 1). Si necesita un oyente simple para un botón, realice una implementación anónima:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Take action.
    }
});

Tiendo a no implementar el OnClickListeneren la actividad, esto se vuelve un poco confuso de vez en cuando (especialmente cuando implementa varios otros controladores de eventos y nadie sabe lo que thisestá haciendo).


Estoy siguiendo lo mismo pero todavía no obtengo resultados para la función, mi código y consulta están aquí: stackoverflow.com/questions/25107427/…
Rocket

8

Prefiero la opción 4, pero tiene sentido intuitivo para mí porque trabajo demasiado en Grails, Groovy y JavaFX. Las conexiones "mágicas" entre la vista y el controlador son comunes en todos. Es importante nombrar bien el método:

En la vista, agregue el método onClick al botón u otro widget:

    android:clickable="true"
    android:onClick="onButtonClickCancel"

Luego, en la clase, maneje el método:

public void onButtonClickCancel(View view) {
    Toast.makeText(this, "Cancel pressed", Toast.LENGTH_LONG).show();
}

Nuevamente, nombre el método claramente, algo que debe hacer de todos modos, y el mantenimiento se convierte en algo natural.

Una gran ventaja es que ahora puede escribir pruebas unitarias para el método. La opción 1 puede hacer esto, pero la 2 y la 3 son más difíciles.


1
Voy a waffle un poco y sugeriré una quinta opción (no, no protagonizada por Bruce Willis :)), una variante de las opciones 2: usar una clase Presenter en un marco Model-View-Presenter para manejar los clics. Hace que las pruebas automatizadas sean MUCHO más fáciles. Consulte este enlace para obtener más información: codelabs.developers.google.com/codelabs/android-testing/…
Steve Gelman

4

La forma más utilizada es la declaración anónima.

    Button send = (Button) findViewById(R.id.buttonSend);
    send.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // handle click
        }
    });

También puede crear el objeto View.OnClickListener y configurarlo como botón más tarde, pero aún necesita anular el método onClick, por ejemplo

View.OnClickListener listener = new View.OnClickListener(){
     @Override
        public void onClick(View v) {
            // handle click
        }
}   
Button send = (Button) findViewById(R.id.buttonSend);
send.setOnClickListener(listener);

Cuando su actividad implementa la interfaz OnClickListener, debe anular el método onClick (Ver v) en el nivel de actividad. Luego puede asignar esta actividad como botón de escucha, porque ya implementa la interfaz y anula el método onClick ()

public class MyActivity extends Activity implements View.OnClickListener{


    @Override
    public void onClick(View v) {
        // handle click
    }


    @Override
    public void onCreate(Bundle b) {
        Button send = (Button) findViewById(R.id.buttonSend);
        send.setOnClickListener(this);
    }

}

(En mi humilde opinión) 4-th enfoque utilizado cuando varios botones tienen el mismo controlador, y puede declarar un método en la clase de actividad y asignar este método a varios botones en el diseño xml, también puede crear un método para un botón, pero en este caso yo prefiero declarar controladores dentro de la clase de actividad.


1

Las opciones 1 y 2 implican el uso de una clase interna que hará que el código sea un poco desordenado. La opción 2 es un poco complicada porque habrá un oyente para cada botón. Si tiene una pequeña cantidad de botones, está bien. Para la opción 4, creo que será más difícil de depurar, ya que tendrá que retroceder y cuarto el código xml y java. Yo personalmente uso la opción 3 cuando tengo que manejar varios clics de botones.


1

Mi muestra, probada en Android Studio 2.1

Definir botón en diseño xml

<Button
    android:id="@+id/btn1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Detección de pulsaciones de Java

Button clickButton = (Button) findViewById(R.id.btn1);
if (clickButton != null) {
    clickButton.setOnClickListener( new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            /***Do what you want with the click here***/
        }
    });
}

1

Para facilitar las cosas como se indica en la Pregunta 2, puede utilizar el método lambda como este para ahorrar memoria variable y evitar navegar hacia arriba y hacia abajo en su clase de vista

//method 1
findViewById(R.id.buttonSend).setOnClickListener(v -> {
          // handle click
});

pero si desea aplicar un evento de clic a su botón de una vez en un método.

puede hacer uso de la Pregunta 3 de @D. Tran responde. Pero no olvide implementar su clase de vista con View.OnClickListener.

En otro para usar la Pregunta # 3 correctamente


1
Esto debe considerarse la respuesta moderna combinada con referencias de métodos OMI. La mayoría de las otras respuestas no mencionan el hecho de que son un código anterior a Java8 en Android.
Ryan The Leach

0

Pregunta n. ° 1: esta es la única forma de manejar los clics de vista.

Pregunta 2 -
Opción # 1 / Opción # 4 - No hay mucha diferencia entre la opción # 1 y la opción # 4. La única diferencia que veo es que en un caso, la actividad es implementar OnClickListener, mientras que, en el otro caso, habría una implementación anónima.

Opción # 2 - En este método se generará una clase anónima. Este método es un poco engorroso, ya que tendría que hacerlo varias veces, si tiene varios botones. Para las clases anónimas, debe tener cuidado al manejar las pérdidas de memoria.

Opción # 3 - Sin embargo, esta es una manera fácil. Por lo general, los programadores intentan no utilizar ningún método hasta que lo escriben y, por tanto, este método no se utiliza mucho. Vería que la mayoría de la gente usa la Opción # 4. Porque es más limpio en términos de código.


Hola Gaurav, gracias por la respuesta. Pero, ¿puede aclarar lo que quiere decir aquí? Para las clases anónimas, debe tener cuidado con el manejo de las pérdidas de memoria. ¿Cómo vienen aquí las pérdidas de memoria?
Budda

Solo debe tener en cuenta que: si crea una clase anónima dentro de un método que podría ser llamado varias veces durante la vida útil de su aplicación, no se crearán varias instancias de una clase, sino varias clases, incluidas las instancias de ellas. Puede evitarlo utilizando clases internas regulares y creando instancias de los oyentes como campos de instancia. Intente reducir las diferentes clases de oyentes haciendo que el estado del oyente sea consciente a través de los argumentos del constructor. Una clase interna regular le brinda el beneficio de constructores personalizados y otros métodos.
Risadinha

0

También hay opciones disponibles en forma de varias bibliotecas que pueden hacer que este proceso sea muy familiar para las personas que han utilizado otros marcos MVVM.

https://developer.android.com/topic/libraries/data-binding/

Muestra un ejemplo de una biblioteca oficial, que le permite vincular botones como este:

<Button
    android:text="Start second activity"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:onClick="@{() -> presenter.showList()}"
/>

0

Paso 1: cree un archivo XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btnClickEvent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me" />
</LinearLayout>

Paso 2: crear MainActivity:

package com.scancode.acutesoft.telephonymanagerapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity implements View.OnClickListener {

    Button btnClickEvent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnClickEvent = (Button) findViewById(R.id.btnClickEvent);
        btnClickEvent.setOnClickListener(MainActivity.this);

    }

    @Override
    public void onClick(View v) {
        //Your Logic
    }
}

HappyCoding!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.