Android: come gestire il clic del pulsante


95

Avendo una solida esperienza in aree non Java e non Android, sto imparando Android.

Ho molta confusione con diverse aree, una di queste è come gestire i clic dei pulsanti. Ci sono almeno 4 modi per farlo (!!!), sono brevemente elencati qui

per motivi di coerenza li elencherò:

  1. Avere un membro della View.OnClickListenerclasse nell'attività e assegnarlo a un'istanza che gestirà la onClicklogica nel onCreatemetodo dell'attività.

  2. Crea "onClickListener" nel metodo di attività "onCreate" e assegnalo al pulsante utilizzando setOnClickListener

  3. Implementa "onClickListener" nell'attività stessa e assegna "this" come listener per il pulsante. Nel caso in cui l'attività abbia pochi pulsanti, l'id del pulsante dovrebbe essere analizzato per eseguire il gestore 'onClick' per il pulsante corretto

  4. Avere un metodo pubblico sull'attività che implementa la logica "onClick" e assegnarlo al pulsante nella dichiarazione xml dell'attività

Domanda 1:

Sono tutti metodi, c'è qualche altra opzione? (Non ho bisogno di nessun altro, solo curioso)

Per me, il modo più intuitivo sarebbe l'ultimo: richiede la minima quantità di codice da digitare ed è il più leggibile (almeno per me).

Tuttavia, non vedo questo approccio ampiamente utilizzato. Quali sono gli svantaggi per usarlo?

Domanda 2:

Quali sono i pro / contro per ciascuno di questi metodi? Per favore condividi la tua esperienza o un buon link.

Qualsiasi feedback è il benvenuto!

PS Ho provato a Google e trovare qualcosa per questo argomento, ma le uniche cose che ho trovato sono la descrizione "come" farlo, non perché è buono o cattivo.

Risposte:


147

Domanda 1: Sfortunatamente quello in cui dici che è più intuitivo è il meno utilizzato in Android. Come ho capito, dovresti separare la tua interfaccia utente (XML) e la funzionalità di calcolo (file di classe Java). Inoltre semplifica il debug. In realtà è molto più facile leggere in questo modo e pensare ad Android imo.

Domanda 2: Credo che i due principalmente utilizzati siano il n. 2 e il n. 3. Userò un pulsante clickButton come esempio.

2

ha la forma di una classe anonima.

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***
            }
        });

Questo è il mio preferito in quanto ha il metodo onClick proprio accanto a dove è stata impostata la variabile del pulsante con findViewById. Sembra molto chiaro e ordinato che tutto ciò che ha a che fare con questa visualizzazione del pulsante clickButton si trovi qui.

Uno svantaggio che il mio collega commenta è che immagina di avere molte visualizzazioni che richiedono un ascoltatore onclick. Puoi vedere che il tuo onCreate diventerà molto lungo. Ecco perché gli piace usare:

3

Supponiamo di avere 5 pulsanti di clic:

Assicurati che la tua attività / frammento implementa 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
    }
}

In questo modo, come spiega il mio collega, è più ordinato ai suoi occhi, poiché tutto il calcolo di onClick viene gestito in un unico punto e non affolla il metodo onCreate. Ma lo svantaggio che vedo è che:

  1. si vedono,
  2. e qualsiasi altro oggetto che potrebbe trovarsi in onCreate utilizzato dal metodo onClick dovrà essere trasformato in un campo.

Fammi sapere se desideri maggiori informazioni. Non ho risposto completamente alla tua domanda perché è una domanda piuttosto lunga. E se trovo alcuni siti amplierò la mia risposta, in questo momento sto solo dando un po 'di esperienza.


1
Per l'opzione 2 ti consigliamo di farlo: clickButton.setOnClickListener (new View.OnClickListener () {@Override public void onClick (View v) {// TODO what you want to do}}); per aiutarlo a risolvere OnClickListener
ColossalChris

L'opzione 3 è probabilmente la più pulita e facile da estendere con il pattern MVP.
Raffaeu

L'opzione 2 può ancora produrre onCreate()non troppo lungo. Le assegnazioni del listener di clic e le classi anonime possono essere scomposte in un metodo di supporto separato chiamato da onCreate().
Nick Alexeev,

@Colossal: non devi farlo. Aggiungi estensione alla classe di attività come "implementa View.OnClickListener".
TomeeNS

10

# 1 Uso frequentemente l'ultimo quando ho pulsanti sul layout che non sono generati (ma ovviamente statici).

Se lo usi nella pratica e in un'applicazione aziendale, presta particolare attenzione qui, perché quando usi source obfuscater come ProGuard, dovrai contrassegnare questi metodi nella tua attività in modo da non essere offuscati.

Per archiviare una sorta di sicurezza in fase di compilazione con questo approccio, dai un'occhiata ad Android Lint ( esempio ).


# 2 Pro e contro per tutti i metodi sono quasi gli stessi e la lezione dovrebbe essere:

Usa ciò che è più appropriato o ti sembra più intuitivo.

Se devi assegnare lo stesso OnClickListenera più istanze di pulsanti, salvalo nell'ambito della classe (# 1). Se hai bisogno di un semplice listener per un Button, effettua un'implementazione anonima:

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

Tendo a non implementare l' OnClickListenerattività nell'attività, questo diventa un po 'confuso di volta in volta (specialmente quando si implementano più altri gestori di eventi e nessuno sa cosa thissta facendo).


Sto seguendo lo stesso ma non ricevo ancora alcun output per la funzione, il mio codice e la mia query sono qui: stackoverflow.com/questions/25107427/…
Rocket

8

Preferisco l'opzione 4, ma per me ha senso intuitivo perché lavoro troppo in Grails, Groovy e JavaFX. Le connessioni "magiche" tra la vista e il controller sono comuni a tutti. È importante dare un nome corretto al metodo:

Nella vista, aggiungi il metodo onClick al pulsante o ad un altro widget:

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

Quindi nella classe, gestisci il metodo:

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

Ancora una volta, dai un nome chiaro al metodo, qualcosa che dovresti fare comunque, e la manutenzione diventa una seconda natura.

Un grande vantaggio è che ora puoi scrivere unit test per il metodo. L'opzione 1 può farlo, ma 2 e 3 sono più difficili.


1
Esprimo un po 'le chiacchiere e suggerisco una quinta opzione (no, non interpretato da Bruce Willis :)), una variante delle opzioni 2: usa una classe Presenter in un framework Model-View-Presenter per gestire i clic. Rende i test automatizzati MOLTO più facili. Dai
Steve Gelman

4

Il modo più utilizzato è la dichiarazione anonima

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

Inoltre puoi creare l'oggetto View.OnClickListener e impostarlo su button in seguito, ma devi comunque sovrascrivere il metodo onClick, ad esempio

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 la tua attività implementa l'interfaccia OnClickListener, devi sovrascrivere il metodo onClick (View v) a livello di attività. Quindi puoi assegnare questa attività come ascoltatore al pulsante, perché implementa già l'interfaccia e sovrascrive il metodo 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) Quarto approccio utilizzato quando più pulsanti hanno lo stesso gestore e puoi dichiarare un metodo nella classe di attività e assegnare questo metodo a più pulsanti nel layout xml, inoltre puoi creare un metodo per un pulsante, ma in questo caso io preferisce dichiarare i gestori all'interno della classe di attività.


1

Le opzioni 1 e 2 prevedono l'uso di una classe interna che renderà il codice un po 'disordinato. L'opzione 2 è un po 'complicata perché ci sarà un ascoltatore per ogni pulsante. Se hai un numero limitato di pulsanti, va bene. Per l'opzione 4 penso che sarà più difficile eseguire il debug in quanto dovrai tornare indietro e per quarto al codice xml e java. Personalmente utilizzo l'opzione 3 quando devo gestire più clic sui pulsanti.


1

Il mio campione, testato in Android Studio 2.1

Definisci il pulsante nel layout xml

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

Rilevazione pulsazioni 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

Per rendere le cose più semplici asp Domanda 2 dichiarata, puoi usare il metodo lambda come questo per salvare la memoria variabile ed evitare di navigare su e giù nella tua classe di visualizzazione

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

ma se desideri applicare l'evento clic al tuo pulsante contemporaneamente in un metodo.

puoi utilizzare la domanda 3 di @D. Risposta di Tran. Ma non dimenticare di implementare la tua classe di visualizzazione con View.OnClickListener.

In altri per usare correttamente la domanda # 3


1
Questa dovrebbe essere considerata la risposta moderna combinata con i riferimenti al metodo IMO. La maggior parte delle altre risposte non richiamano il fatto che sono un vecchio codice pre Java8 su Android.
Ryan The Leach

0

Domanda n. 1 - Questi sono l'unico modo per gestire i clic di visualizzazione.

Domanda 2 -
Opzione # 1 / Opzione # 4 - Non c'è molta differenza tra l'opzione # 1 e l'opzione # 4. L'unica differenza che vedo è che in un caso l'attività sta implementando OnClickListener, mentre, nell'altro caso, ci sarebbe un'implementazione anonima.

Opzione # 2: in questo metodo verrà generata una classe anonima. Questo metodo è un po 'macchinoso, poiché dovresti farlo più volte, se hai più pulsanti. Per le classi anonime, devi stare attento a gestire le perdite di memoria.

Opzione n. 3 - Tuttavia, questo è un modo semplice. Di solito, i programmatori cercano di non utilizzare alcun metodo fino a quando non lo scrivono, e quindi questo metodo non è ampiamente utilizzato. Vedresti che per lo più le persone usano l'opzione n. 4. Perché è più pulito in termini di codice.


Ciao Gaurav, grazie per la risposta. Ma puoi chiarire cosa intendi qui: per le classi anonime, devi stare attento a gestire le perdite di memoria. Come vengono qui le perdite di memoria?
Budda

Devi solo essere consapevole che: se crei una classe anonima all'interno di un metodo che potrebbe essere chiamato più volte durante la durata della tua app non verranno create più istanze di una classe ma diverse classi incluse le istanze di esse. È possibile evitarlo utilizzando classi interne regolari e istanziando i listener come campi di istanza. Prova a ridurre le diverse classi di ascoltatori rendendo consapevole lo stato dell'ascoltatore tramite gli argomenti del costruttore. Una normale classe interna offre il vantaggio di costruttori personalizzati e altri metodi.
Risadinha

0

Sono disponibili anche opzioni sotto forma di varie librerie che possono rendere questo processo molto familiare alle persone che hanno utilizzato altri framework MVVM.

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

Mostra un esempio di una libreria ufficiale, che ti consente di associare pulsanti come questo:

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

0

Passaggio 1: crea un file 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>

Passaggio 2: crea attività principale:

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!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.