La mejor práctica para definir eventos de botón en Android

Tengo un Layout definido en XML que consiste en varios Button .

Actualmente estoy haciendo esto en el método OnCreate para definir los manejadores de eventos contra los botones:

 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button newPicButton = (Button)findViewById(R.id.new_button); newPicButton.setOnClickListener(btnListener); ..... similarly for other buttons too ..... } 

Dentro del evento onClick Button , onClick una cámara con Intent de obtener una imagen y dentro de la onActivityResult llamada onActivityResult estoy de nuevo configurando los manejadores de eventos junto con la configuración de la View esta manera:

 protected void onActivityResult(int requestCode, int resultCode, Intent data) { setContentView(R.layout.main); Button newPicButton = (Button)findViewById(R.id.new_button); newPicButton.setOnClickListener(btnListener); ...similarly for other buttons too } 

Soy nuevo en Android y este enfoque de redefinir un evento cada vez me parece bastante sucio. Me gustaría saber cuál es la mejor práctica en términos de definición de manejadores de eventos de botón en escenarios como este.

Editar: pegar mi clase completa

 public class CameraAppActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button newPicButton = (Button)findViewById(R.id.new_button); newPicButton.setOnClickListener(btnListener); } //---create an anonymous class to act as a button click listener--- private OnClickListener btnListener = new OnClickListener() { public void onClick(View v) { //Intent newPicIntent = new Intent(v.getContext(), NewPictureActivity.class); //startActivityForResult(newPicIntent, 0); Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(cameraIntent, 999); } }; protected void onActivityResult(int requestCode, int resultCode, Intent data) { setContentView(R.layout.main); Button newPicButton = (Button)findViewById(R.id.new_button); newPicButton.setOnClickListener(btnListener); //if I comment last two lines nothing happens when I click on button } 

La pregunta principal es

 setContentView(R.layout.main); Button newPicButton = (Button)findViewById(R.id.new_button); newPicButton.setOnClickListener(btnListener); 

Volver a registrar eventos dentro de onActivityResult … ¿es el enfoque correcto? ¿O estoy haciendo algo mal? Porque si no me vuelvo a registrar, no ocurre nada cuando hago clic en el botón.

Por qué no registrar el evento onClick en el diseño XML y luego manejarlo en el código. Así es como lo haría:

  

y ahora crea un método que manejaría los clics

 public void onBtnClicked(View v){ if(v.getId() == R.id.my_btn){ //handle the click here } } 

Alternativamente, puede configurar OnClickListener individualmente para cada elemento en el código. Luego use if / else o cambie las declaraciones para determinar el origen.

De esta forma, puede tener un método que maneje todos los botones de un diseño.

ACTUALIZAR:
Aunque este es un enfoque válido, recomendaría encarecidamente la segunda opción. Es más limpio y más fácil de mantener, especialmente cuando trabajas con fragmentos.

Este es el mejor enfoque con código:

  public class MyTest extends Activity implements OnClickListener{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //... some other code here to init the layout Button btn1 = (Button)findViewById(R.id.button1); Button btn2 = (Button)findViewById(R.id.button2); btn1.setOnClickListener(this); btn2.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()){ case R.id.button1: break; case R.id.button2: break; } } } 

La nueva clase con una interfaz solo es buena si deseas desacoplar la implementación (cuando quieres usar el mismo código de clase en otro lugar, moverlo a otro archivo de clase separado, etc.) pero, en general, si estás haciendo cosas conectadas con la actividad actual en la que se encuentra y las implementaciones onClick dependen de que se ejecute con referencia a los objetos definidos, definitivamente debe usar el método que sugerí.

Crear interfaces de clase solo es bueno cuando quieres lograr la comunicación entre clases o actividades separadas y mantener las cosas separadas. Aparte de eso, es una mala práctica crear subclases para esto.

este es el mejor enfoque

 @Override public void onCreate(Bundle savedInstanceState) { button1.setOnClickListener(onClickListener); button2.setOnClickListener(onClickListener); button3.setOnClickListener(onClickListener); } private OnClickListener onClickListener = new OnClickListener() { @Override public void onClick(final View v) { switch(v.getId()){ case R.id.button1: //DO something break; case R.id.button2: //DO something break; case R.id.button3: //DO something break; } } }; 

No hay una mejor práctica definida. Depende mucho del caso de uso. Puede definirlos en su diseño XML usando el atributo onClick del botón.

Ejemplo XML:

   

Ejemplo de Java:

 // stuff public void myClickMethod(View v) { // more stuff } 

De esta forma, no tiene que implementar OnClickListener usted mismo. Puede asignar a cada botón el mismo método onClick y luego simplemente decidir en función de la vista qué acción desencadenar o puede tener un método separado para cada botón.

En general, OnClickListener utilizar un OnClickListener para más de un botón. Es más fácil entender lo que se supone que debe hacer cada oyente si usa nombres descriptivos, que es lo que debe hacer de todos modos.

Me gusta la forma DI “moderna” usando Butter Knife :

  1. Declara tu vista
 @InjectView(R.id.buttonAlert) Button buttonAlert; 
  1. Inyectar todos los recursos anotados
 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); } 
  1. Anota e implementa tu método onClick
 @OnClick(R.id.buttonAlert) public void alertClicked(View v){ // your logic } 

@Hasan Este es el mejor enfoque que he encontrado y que funciona para mí cada vez sin problemas.

  • En Layout.xml define onClick para el botón

       
  • En el archivo R.string agrega la siguiente línea

string name = “method”> buttonFunction

  • En el archivo sample.java se llamará a la función definir en R.string al hacer clic en el botón y se verá algo así como

    public void buttonFunction (Ver vista) {// hacer que te parezca con el clic del botón}

Su actividad debe implementar OnClickListener y debe escribir todo su manejo de eventos para todos los botones dentro del único método OnCLick ().

El problema es el objeto para el botón newPicButton se está creando como un objeto local que es válido solo en el scope de la función onCreate y tan pronto como el código sale de esa función, el colector de garabatos desasigna el objeto para el botón. lo que debe hacer es declarar el nuevo objetoPicButton fuera de cualquier método y luego en el método onCreate asignarle un oyente. Esto resolverá su problema y espero haber explicado por qué no ocurre nada cuando elimina el código para el nuevoPicButton en el método onActivityResult 🙂

Sé que esto es antiguo, pero si alguien se pregunta por qué no puede agregar onClickListener desde onActivityResult , es porque el botón es nulo. Si lo inicializa una vez más (tal como lo hizo en onCreate ), puede agregar el oyente. Tenga cuidado, sin embargo, todo lo demás también será nulo, así que si está tomando datos de un EditText , por ejemplo, también debe inicializar eso (una simple comprobación de si el objeto es nulo en el lister hará el truco) )

Así es como lo hice:

  1. En el archivo XML de botones, configure android: onClick = “onClick”.
  2. En su Actividad, implemente View.OnClickListener.
  3. Dentro del método onClick use la tecla Cambiar (como se muestra a continuación).

@Anular

 public void onClick(View view) { Intent intent; switch(view.getId()){ case R.id.home_button: //DO something intent = new Intent(HashTagActivity.this,MainActivity.class); startActivity(intent); break; case R.id.back_button: //DO something intent = new Intent(HashTagActivity.this,ClassActivity.class); startActivity(intent); break; case R.id.favorite_button: //DO something break; case R.id.copy_button: //DO something break; } } 

Funciona de maravilla.