Android: Wie man mit dem Klicken auf eine Schaltfläche umgeht

95

Ich habe eine solide Erfahrung im Nicht-Java- und Nicht-Android-Bereich und lerne Android.

Ich habe viel Verwirrung mit verschiedenen Bereichen, einer davon ist der Umgang mit Tastenklicks. Es gibt mindestens 4 Art und Weise zu tun , dass (!!!), sie kurz sind aufgelistet hier

Aus Konsistenzgründen werde ich sie auflisten:

  1. Haben Sie ein Mitglied der View.OnClickListenerKlasse in der Aktivität und weisen Sie es einer Instanz zu, die die onClickLogik in der onCreateAktivitätsmethode verarbeitet.

  2. Erstellen Sie 'onClickListener' in der Aktivitätsmethode 'onCreate' und weisen Sie es der Schaltfläche mit setOnClickListener zu

  3. Implementieren Sie 'onClickListener' in der Aktivität selbst und weisen Sie 'this' als Listener für die Schaltfläche zu. Für den Fall, dass die Aktivität nur wenige Schaltflächen enthält, sollte die Schaltflächen-ID analysiert werden, um den 'onClick'-Handler für die richtige Schaltfläche auszuführen

  4. Verfügen Sie über eine öffentliche Methode für die Aktivität, die die 'onClick'-Logik implementiert, und weisen Sie sie der Schaltfläche in der Aktivitäts-XML-Deklaration zu

Frage 1:

Sind das alles Methoden, gibt es eine andere Option? (Ich brauche keine andere, nur neugierig)

Für mich wäre der intuitivste Weg der neueste: Er erfordert die geringste Menge an Code und ist am besten lesbar (zumindest für mich).

Ich sehe diesen Ansatz jedoch nicht weit verbreitet. Was sind die Nachteile für die Verwendung?

Frage 2:

Was sind Vor- und Nachteile für jede dieser Methoden? Bitte teilen Sie entweder Ihre Erfahrungen oder einen guten Link.

Jedes Feedback ist willkommen!

PS Ich habe versucht, bei Google etwas für dieses Thema zu finden, aber die einzigen Dinge, die ich gefunden habe, sind die Beschreibung "wie", nicht warum es gut oder schlecht ist.

Budda
quelle

Antworten:

147

Frage 1: Leider wird diejenige, in der Sie sagen, dass sie am intuitivsten ist, in Android am wenigsten verwendet. Soweit ich weiß, sollten Sie Ihre Benutzeroberfläche (XML) und die Rechenfunktionalität (Java-Klassendateien) trennen. Dies erleichtert auch das Debuggen. Es ist tatsächlich viel einfacher, auf diese Weise zu lesen und über Android imo nachzudenken.

Frage 2: Ich glaube, die beiden hauptsächlich verwendeten sind # 2 und # 3. Ich werde einen Button clickButton als Beispiel verwenden.

2

ist in Form einer anonymen Klasse.

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

Dies ist mein Favorit, da die onClick-Methode direkt neben der Stelle steht, an der die Schaltflächenvariable mit der findViewById festgelegt wurde. Es scheint sehr ordentlich und ordentlich zu sein, dass sich alles, was mit dieser ClickButton Button View zu tun hat, hier befindet.

Ein Nachteil, den mein Kollege kommentiert, ist die Vorstellung, dass Sie viele Ansichten haben, die einen Klick-Listener benötigen. Sie können sehen, dass Ihr onCreate sehr lang wird. Deshalb benutzt er gerne:

3

Angenommen, Sie haben 5 clickButtons:

Stellen Sie sicher, dass Ihre Aktivität / Ihr Fragment OnClickListener implementiert

// 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
    }
}

Wie mein Kollege erklärt, ist dies in seinen Augen ordentlicher, da die gesamte onClick-Berechnung an einem Ort durchgeführt wird und die onCreate-Methode nicht überfüllt ist. Aber der Nachteil, den ich sehe, ist, dass die:

  1. sieht sich selbst,
  2. und jedes andere Objekt, das sich möglicherweise in onCreate befindet und von der onClick-Methode verwendet wird, muss in ein Feld umgewandelt werden.

Lassen Sie mich wissen, wenn Sie weitere Informationen wünschen. Ich habe Ihre Frage nicht vollständig beantwortet, da es sich um eine ziemlich lange Frage handelt. Und wenn ich einige Websites finde, werde ich meine Antwort erweitern. Im Moment gebe ich nur einige Erfahrungen.

Dumamilk
quelle
1
Für Option 2 möchten Sie es machen: clickButton.setOnClickListener (neuer View.OnClickListener () {@Override public void onClick (View v) {// TODO was Sie tun möchten}}); um es zu lösen OnClickListener
ColossalChris
Option 3 ist wahrscheinlich die sauberste und am einfachsten mit MVP-Muster zu erweiternde.
Raffaeu
Option 2 kann immer noch produzieren onCreate(), was nicht sehr lang ist. Die Click-Listener-Zuweisungen und die anonymen Klassen können in eine separate Hilfsmethode zerlegt werden, von der aus aufgerufen wird onCreate().
Nick Alexeev
@ Colossal: Du musst es nicht tun. Fügen Sie der Aktivitätsklasse eine Erweiterung hinzu, z. B. "Implementiert View.OnClickListener".
TomeeNS
10

# 1 Ich benutze die letzte häufig, wenn Schaltflächen im Layout nicht generiert werden (aber offensichtlich statisch).

Wenn Sie es in der Praxis und in einer Geschäftsanwendung verwenden, achten Sie hier besonders darauf, denn wenn Sie Quell-Obfuscater wie ProGuard verwenden, müssen Sie diese Methoden in Ihrer Aktivität als nicht verschleiert markieren.

Schauen Sie sich Android Lint ( Beispiel ) an, um mit diesem Ansatz eine Art Sicherheit zur Kompilierungszeit zu archivieren .


# 2 Vor- und Nachteile für alle Methoden sind fast gleich und die Lektion sollte sein:

Verwenden Sie, was für Sie am besten geeignet oder am intuitivsten ist.

Wenn Sie dasselbe OnClickListenermehreren Instanzen von Schaltflächen zuweisen müssen , speichern Sie es im Klassenbereich (Nr. 1). Wenn Sie einen einfachen Listener für einen Button benötigen, führen Sie eine anonyme Implementierung durch:

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

Ich neige dazu, das OnClickListenerin der Aktivität nicht zu implementieren , dies wird von Zeit zu Zeit etwas verwirrend (insbesondere wenn Sie mehrere andere Event-Handler implementieren und niemand weiß, was thisalles tut).

Lukas Knuth
quelle
8

Ich bevorzuge Option 4, aber es macht für mich intuitiv Sinn, weil ich viel zu viel in Grails, Groovy und JavaFX arbeite. "Magische" Verbindungen zwischen der Ansicht und dem Controller sind allen gemeinsam. Es ist wichtig, die Methode gut zu benennen:

Fügen Sie in der Ansicht die onClick-Methode zur Schaltfläche oder einem anderen Widget hinzu:

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

Behandeln Sie dann in der Klasse die Methode:

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

Nennen Sie die Methode wieder klar, was Sie sowieso tun sollten, und die Wartung wird zur Selbstverständlichkeit.

Ein großer Vorteil ist, dass Sie jetzt Unit-Tests für die Methode schreiben können. Option 1 kann dies tun, aber 2 und 3 sind schwieriger.

Steve Gelman
quelle
1
Ich werde ein wenig waffeln und eine fünfte Option vorschlagen (nein, ohne Bruce Willis :)), eine Variante von Option 2: Verwenden Sie eine Presenter-Klasse in einem Model-View-Presenter-Framework, um Klicks zu verarbeiten. Es macht das automatisierte Testen VIEL einfacher. Weitere
Steve Gelman
4

Am häufigsten wird eine anonyme Erklärung verwendet

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

Sie können auch das View.OnClickListener-Objekt erstellen und es später auf die Schaltfläche setzen. Sie müssen jedoch beispielsweise die onClick-Methode weiterhin überschreiben

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

Wenn Ihre Aktivität die OnClickListener-Schnittstelle implementiert, müssen Sie die onClick (View v) -Methode auf Aktivitätsebene überschreiben. Anschließend können Sie diese Aktivität als Listener für die Schaltfläche zuweisen, da sie bereits die Schnittstelle implementiert und die onClick () -Methode überschreibt

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. Ansatz, der verwendet wird, wenn mehrere Schaltflächen denselben Handler haben und Sie eine Methode in der Aktivitätsklasse deklarieren und diese Methode mehreren Schaltflächen im XML-Layout zuweisen können. Sie können auch eine Methode für eine Schaltfläche erstellen, aber in diesem Fall I. deklarieren Sie lieber Handler innerhalb der Aktivitätsklasse.

Georgy Gobozov
quelle
1

Option 1 und 2 beinhalten die Verwendung einer inneren Klasse, die den Code durcheinander bringt. Option 2 ist etwas chaotisch, da es für jede Taste einen Listener gibt. Wenn Sie eine kleine Anzahl von Tasten haben, ist dies in Ordnung. Für Option 4 wird dies meiner Meinung nach schwieriger zu debuggen sein, da Sie zurückgehen und den XML- und Java-Code vierteln müssen. Ich persönlich verwende Option 3, wenn ich mit mehreren Tastenklicks umgehen muss.

CChi
quelle
1

Mein Beispiel, getestet in Android Studio 2.1

Schaltfläche im XML-Layout definieren

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

Java-Pulsationserkennung

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
quelle
1

Zur Vereinfachung der Frage 2 können Sie die Lambda-Methode wie diese verwenden, um variablen Speicher zu sparen und das Navigieren in Ihrer Ansichtsklasse nach oben und unten zu vermeiden

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

Wenn Sie jedoch in einer Methode das Klickereignis sofort auf Ihre Schaltfläche anwenden möchten.

Sie können Frage 3 von @D verwenden. Tran Antwort. Vergessen Sie jedoch nicht, Ihre Ansichtsklasse mit zu implementieren View.OnClickListener.

In anderen, um Frage 3 richtig zu verwenden

Michael
quelle
1
Dies sollte als moderne Antwort in Kombination mit Methodenreferenzen IMO betrachtet werden. Die meisten anderen Antworten geben nicht an, dass es sich um alten Code vor Java8 auf Android handelt.
Ryan The Leach
0

Frage 1 - Dies ist die einzige Möglichkeit, mit Ansichtsklicks umzugehen.

Frage 2 -
Option 1 / Option 4 - Es gibt keinen großen Unterschied zwischen Option 1 und Option 4. Der einzige Unterschied, den ich sehe, besteht in einem Fall darin, den OnClickListener zu implementieren, während in dem anderen Fall eine anonyme Implementierung erfolgt.

Option 2 - Bei dieser Methode wird eine anonyme Klasse generiert. Diese Methode ist etwas umständlich, da Sie sie mehrmals ausführen müssen, wenn Sie mehrere Schaltflächen haben. Bei anonymen Klassen müssen Sie vorsichtig mit Speicherlecks umgehen.

Option 3 - Dies ist jedoch ein einfacher Weg. Normalerweise versuchen Programmierer, keine Methode zu verwenden, bis sie sie schreiben, und daher ist diese Methode nicht weit verbreitet. Sie werden sehen, dass die meisten Leute Option 4 verwenden. Weil es in Bezug auf Code sauberer ist.

Gaurav Arora
quelle
Hallo Gaurav, danke für die Antwort. Aber können Sie bitte klarstellen, was Sie hier meinen: Bei anonymen Klassen müssen Sie vorsichtig mit Speicherlecks umgehen. Wie kommen Speicherlecks hierher?
Budda
Sie müssen nur Folgendes beachten: Wenn Sie eine anonyme Klasse innerhalb einer Methode erstellen, die während der Lebensdauer Ihrer App möglicherweise mehrmals aufgerufen wird, werden nicht mehrere Instanzen einer Klasse erstellt, sondern mehrere Klassen, einschließlich Instanzen davon. Sie können dies vermeiden, indem Sie reguläre innere Klassen verwenden und die Listener als Instanzfelder instanziieren. Versuchen Sie, die verschiedenen Listener-Klassen zu reduzieren, indem Sie den Listener-Status über Konstruktorargumente bekannt machen. Eine reguläre innere Klasse bietet Ihnen den Vorteil von benutzerdefinierten Konstruktoren und anderen Methoden.
Risadinha
0

Es gibt auch Optionen in Form verschiedener Bibliotheken, die diesen Prozess Personen, die andere MVVM-Frameworks verwendet haben, sehr vertraut machen können.

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

Zeigt ein Beispiel einer offiziellen Bibliothek, mit der Sie Schaltflächen wie folgt binden können:

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

Schritt 1: Erstellen Sie eine XML-Datei:

<?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>

Schritt 2: Erstellen Sie 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
quelle