Android: como lidar com o clique do botão

95

Tendo uma sólida experiência na área não Java e não Android, estou aprendendo Android.

Tenho muita confusão com diferentes áreas, uma delas é como lidar com cliques de botão. Existem pelo menos 4 maneiras de fazer isso (!!!), elas estão brevemente listadas aqui

para fins de consistência, vou listá-los:

  1. Tenha um membro da View.OnClickListenerclasse na atividade e atribua-o a uma instância que tratará da onClicklógica no onCreatemétodo da atividade.

  2. Crie 'onClickListener' no método de atividade 'onCreate' e atribua-o ao botão usando setOnClickListener

  3. Implemente 'onClickListener' na própria atividade e atribua 'this' como um ouvinte para o botão. No caso de a atividade ter poucos botões, o id do botão deve ser analisado para executar o manipulador 'onClick' para o botão apropriado

  4. Tenha um método público na atividade que implementa a lógica 'onClick' e atribua-o ao botão na declaração XML da atividade

Questão 1:

São todos métodos, existe alguma outra opção? (Não preciso de mais nenhum, só curiosidade)

Para mim, a forma mais intuitiva seria a mais recente: requer a menor quantidade de código para ser digitada e é a mais legível (pelo menos para mim).

Porém, não vejo essa abordagem amplamente usada. Quais são os contras de usá-lo?

Questão 2:

Quais são os prós / contras de cada um desses métodos? Por favor, compartilhe sua experiência ou um bom link.

Qualquer feedback é bem-vindo!

PS Eu tentei pesquisar no Google e encontrar algo sobre esse tópico, mas as únicas coisas que encontrei foram a descrição de "como" fazer isso, não por que isso é bom ou ruim.

Budda
fonte

Respostas:

147

Questão 1: Infelizmente aquele em que você diz ser mais intuitivo é o menos usado no Android. Pelo que entendi, você deve separar sua interface do usuário (XML) e a funcionalidade computacional (arquivos de classe Java). Também facilita a depuração. Na verdade, é muito mais fácil ler dessa forma e pensar no Android imo.

Pergunta 2: Acredito que os dois mais usados ​​são os 2 e 3. Vou usar um botão clickButton como exemplo.

2

está na forma de uma classe 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 é o meu favorito, pois tem o método onClick ao lado de onde a variável do botão foi definida com findViewById. Parece muito limpo e organizado que tudo o que lida com esta visualização de botão clickButton está localizado aqui.

Um golpe que meu colega de trabalho comenta é que imagine que você tenha muitas visualizações que precisam de um ouvinte onclick. Você pode ver que seu onCreate ficará muito longo. É por isso que ele gosta de usar:

3

Digamos que você tenha 5 botões de clique:

Certifique-se de que sua atividade / 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
    }
}

Assim, como explica meu colega de trabalho, é mais organizado aos olhos dele, já que todo o cálculo onClick é feito em um só lugar e não sobrecarrega o método onCreate. Mas a desvantagem que vejo é que:

  1. se vêem,
  2. e qualquer outro objeto que possa estar localizado em onCreate usado pelo método onClick terá que ser transformado em um campo.

Deixe-me saber se você deseja obter mais informações. Não respondi totalmente a sua pergunta porque é uma pergunta muito longa. E se eu encontrar alguns sites, vou expandir minha resposta, agora estou apenas dando um pouco de experiência.

leite dumamilk
fonte
1
Para a opção 2, você desejará torná-lo: clickButton.setOnClickListener (new View.OnClickListener () {@Override public void onClick (View v) {// TODO o que você deseja fazer}}); para ajudá-lo a resolver OnClickListener
ColossalChris
A opção 3 é provavelmente a mais limpa e fácil de estender com o padrão MVP.
Raffaeu
A opção 2 ainda pode produzir onCreate()não muito longa. As atribuições do ouvinte de clique e as classes anônimas podem ser fatoradas em um método auxiliar separado que é chamado de onCreate().
Nick Alexeev
@Colossal: Você não precisa fazer isso. Adicione uma extensão à classe de atividade como "implementa View.OnClickListener".
TomeeNS
10

# 1 Eu uso o último freqüentemente quando tenho botões no layout que não são gerados (mas estáticos obviamente).

Se você o usa na prática e em um aplicativo de negócios, preste atenção extra aqui, porque quando você usa o ofuscador de origem como o ProGuard, você precisará marcar esses métodos em sua atividade para não serem ofuscados.

Para arquivar algum tipo de segurança de tempo de compilação com essa abordagem, dê uma olhada no Android Lint ( exemplo ).


# 2 Os prós e contras de todos os métodos são quase os mesmos e a lição deve ser:

Use o que for mais apropriado ou mais intuitivo para você.

Se você tiver que atribuir o mesmo OnClickListenera várias instâncias de botão, salve-o no escopo da classe (# 1). Se você precisar de um ouvinte simples para um botão, faça uma implementação anônima:

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

Tendo a não implementar o OnClickListenerna atividade, isso fica um pouco confuso de vez em quando (especialmente quando você implementa vários outros manipuladores de eventos e ninguém sabe o que thisestá fazendo).

Lukas Knuth
fonte
Estou seguindo o mesmo, mas ainda não obtive saída para a função, meu código e consulta estão aqui: stackoverflow.com/questions/25107427/…
Rocket
8

Eu prefiro a opção 4, mas faz sentido intuitivo para mim porque eu trabalho demais em Grails, Groovy e JavaFX. Conexões "mágicas" entre a visualização e o controlador são comuns em todos. É importante nomear bem o método:

Na visualização, adicione o método onClick ao botão ou outro widget:

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

Em seguida, na aula, manipule o método:

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

Novamente, nomeie o método claramente, algo que você deve fazer de qualquer maneira, e a manutenção torna-se uma segunda natureza.

Uma grande vantagem é que agora você pode escrever testes de unidade para o método. A opção 1 pode fazer isso, mas 2 e 3 são mais difíceis.

Steve Gelman
fonte
1
Vou waffle um pouco e sugerir uma quinta opção (não, não estrelado por Bruce Willis :)), uma variante das opções 2: usar uma classe Presenter em uma estrutura Model-View-Presenter para lidar com cliques. Isso torna o teste automatizado MUITO mais fácil. Confira este link para obter melhores informações: codelabs.developers.google.com/codelabs/android-testing/…
Steve Gelman
4

A forma mais usada é, declaração anônima

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

Além disso, você pode criar o objeto View.OnClickListener e defini-lo como botão mais tarde, mas você ainda precisa substituir o método onClick, por exemplo

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

Quando sua atividade implementa a interface OnClickListener, você deve substituir o método onClick (Exibir v) no nível de atividade. Então você pode atribuir esta atividade como ouvinte do botão, porque ele já implementa a interface e substitui o 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);
    }

}

(imho) 4ª abordagem usada quando vários botões têm o mesmo manipulador, e você pode declarar um método na classe de atividade e atribuir este método a vários botões no layout xml, você também pode criar um método para um botão, mas neste caso eu prefira declarar manipuladores dentro da classe de atividade.

Georgy gobozov
fonte
1

As opções 1 e 2 envolvem o uso de uma classe interna que tornará o código uma espécie de desordem. A opção 2 é meio confusa porque haverá um ouvinte para cada botão. Se você tiver um pequeno número de botões, tudo bem. Para a opção 4, acho que será mais difícil depurar, pois você terá que voltar e quarta o código xml e java. Eu pessoalmente uso a opção 3 quando preciso lidar com vários cliques de botão.

CChi
fonte
1

Minha amostra, testada no Android Studio 2.1

Definir botão no layout xml

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

Detecção de pulsação 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***/
        }
    });
}
Webserveis
fonte
1

Para tornar as coisas mais fáceis, asp Questão 2 declarada, você pode fazer uso do método lambda como este para economizar memória variável e para evitar navegar para cima e para baixo em sua classe de visualização

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

mas se você deseja aplicar o evento de clique ao botão de uma vez em um método.

você pode usar a Questão 3 de @D. Resposta Tran. Mas não se esqueça de implementar sua classe de visualização comView.OnClickListener .

Em outro, para usar a Pergunta # 3 corretamente

Michael
fonte
1
Esta deve ser considerada a resposta moderna combinada com as referências do método IMO. A maioria das outras respostas não chama a atenção para o fato de serem códigos anteriores ao Java8 no Android.
Ryan The Leach
0

Pergunta nº 1 - Essa é a única maneira de lidar com cliques de visualização.

Pergunta # 2 -
Opção # 1 / Opção # 4 - Não há muita diferença entre a opção # 1 e a opção # 4. A única diferença que vejo é que a atividade de um caso está implementando OnClickListener, enquanto, no outro caso, haveria uma implementação anônima.

Opção nº 2 - Neste método, uma classe anônima será gerada. Este método é um pouco complicado, pois você precisará fazer isso várias vezes, se tiver vários botões. Para classes anônimas, você deve ter cuidado ao lidar com vazamentos de memória.

Opção nº 3 - No entanto, esta é uma maneira fácil. Normalmente, os programadores tentam não usar nenhum método até que o escrevam e, portanto, esse método não é amplamente utilizado. Você veria que a maioria das pessoas usa a Opção # 4. Porque é mais limpo em termos de código.

Gaurav Arora
fonte
Oi Gaurav, obrigado pela resposta. Mas você pode esclarecer o que quer dizer aqui: Para classes anônimas, você deve ter cuidado ao lidar com vazamentos de memória. Como vazamentos de memória vêm aqui?
Budda
Você apenas precisa estar ciente de que: se você criar uma classe anônima dentro de um método que pode ser chamado várias vezes durante o tempo de vida de seu aplicativo, não serão criadas várias instâncias de uma classe, mas várias classes, incluindo instâncias delas. Você pode evitar isso usando classes internas regulares e instanciando os ouvintes como campos de instância. Tente reduzir as diferentes classes de ouvintes tornando o estado do ouvinte ciente por meio de argumentos do construtor. Uma classe interna regular oferece o benefício de construtores personalizados e outros métodos.
Risadinha 15/10/2013
0

Também existem opções disponíveis na forma de várias bibliotecas que podem tornar esse processo muito familiar para pessoas que usaram outros frameworks MVVM.

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

Mostra um exemplo de biblioteca oficial, que permite vincular botões como este:

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

Etapa 1: Crie um arquivo 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>

Etapa 2: Criar 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!

Manikanta Reddy
fonte