2015-05-06 21 views
36

Angenommen, wir haben eine Aktivität mit vielen Ansichten, auf der OnClickListener registriert werden soll.Die beste Methode zum Implementieren von View.OnClickListener in android

Der gängigste Weg, dies zu implementieren, ist die Aktivität-Subklassen-Umsetzung der OnClickListener, so etwas zu lassen:

public class ActivityMain extends Activity implements View.OnClickListener 
{ 
    @Override 
    public void onClick(View view) 
    { 
     switch (view.getId()) 
     { 
      //handle multiple view click events 
     } 
    } 
} 

Die Art, wie ich es umsetzen möchte, ist eine private Klasse innerhalb des Aktivitäts- zu erstellen Unterklasse und lassen die innere Klasse die OnClickListener implementieren:

public class ActivityMain extends Activity implements View.OnClickListener 
{ 
    private class ClickListener implements View.OnClickListener 
    { 
     @Override 
     public void onClick(View view) 
     { 
      switch (view.getId()) 
      { 
       //handle multiple view click events 
      } 
     } 
    } 
} 

diese Weise wird der Code scheint besser organisiert und leicht zu pflegen.

Außerdem, über "Is-a", "Has-a" -Beziehungen sprechend, scheint letzteres eine gute Übung zu sein, weil die Activity-Subclass nun eine "Has-a" -Beziehung mit dem ClickListener haben würde. Während in der früheren Methode würden wir sagen, dass unsere Aktivität-Subclass "Is-a" ClickListener, die nicht vollständig wahr ist.

Beachten Sie, dass ich nicht mit dem Speicheraufwand beschäftigt sind, den der letztere verursachen würde.

Auch das Hinzufügen von onClick-Tag in XML kommt völlig in Frage.

Also, was ist der beste Weg, um einen ClickListener zu implementieren?

Bitte schlagen keine Bibliotheken wie RoboGuice oder Buttermesser usw.

UPDATE:

Ich möchte den Ansatz teilen, die ich schließlich angenommen.

Ich implementiere den Hörer direkt in Aktivität/Fragment.

Soweit OOP-Design betroffen ist. Der "HAS-A" Ansatz bietet keine praktischen Vorteile und nimmt sogar mehr Speicher in Anspruch. Angesichts der Menge der geschachtelten Klassen (und des Speicheraufwands), die wir für jeden ähnlichen Listener, den wir implementieren, erstellen werden, sollte dieser Ansatz klar vermieden werden.

+1

Ihre Frage ist sehr subjektiv, was Sie mit „best“ bedeuten. Was ist dein Ziel? – cyroxis

+0

Ziel ist einfach, folgen Best Practices :) –

+1

Ihr 'ClickListener' ist eine innere nicht-statische Klasse die Kopplung dieser 'hat-a' ist nicht anders, als wenn Ihre Klasse' Activity' 'View.OnClickListener' implementiert. Dies liegt daran, dass Ihr innerer 'ClickListener' eine Instanz von' ActivityMain' benötigt und wirklich nicht wiederverwendet werden kann. Ich würde argumentieren, dass Sie über Engineering sind und nicht wirklich etwas gewinnen. –

Antwort

38

Zunächst gibt es keine von Android definierte Best Practice für die Registrierung von Klick-Listenern. Es hängt völlig von Ihrem Anwendungsfall ab.

Die Implementierung der View.OnClickListener Schnittstelle zu Activity ist der Weg zu gehen. Wie Android empfiehlt dringend Schnittstelle Implementierung immer und immer wieder, ob es eine Aktivität oder Fragment ist.

Nun, wie Sie beschrieben:

public class ActivityMain extends Activity implements View.OnClickListener 
{ 
    private class ClickListener implements View.OnClickListener 
    { 
     @Override 
     public void onClick(View view) 
     { 
      switch (view.getId()) 
      { 
       //handle multiple view click events 
      } 
     } 
    } 
} 

Dieser Ihr Ansatz ist. Jetzt ist es Ihre Art der Implementierung und es ist nichts falsch daran, wenn Sie nicht mit Speicheraufwand beschäftigt sind. Aber was ist der Vorteil der Schaffung der inneren Klasse und der Implementierung der View.OnClickListener, wenn Sie einfach implementieren, dass in der Hauptklasse, die auch zu der Code-Klarheit und Einfachheit, die Sie benötigen, führen kann.

So ist es eher nur eine Diskussion, die bestmögliche Lösung für die Umsetzung der View.OnClickListener bekommen, denn wenn man mit dem praktischen Standpunkt aus jeder gehen, werden Sie nach einer Lösung gehen, die eine effiziente und einfache Speicher ist.

Also würde ich den konventionellen Weg bevorzugen. Es hält Dinge einfach und effizient. Überprüfen Sie den Code unten:

@Override 
public void onClick(View view) 
{ 
    switch (view.getId()) 
    { 
     //handle multiple view click events 
    } 
} 

PS: Ihr Ansatz wird auf jeden Fall Codezeilen erhöhen: P;)

+1

Was bedeutet LOC? –

+0

@AliKazi: Tut mir leid, ich bin ein bisschen spät. LOC bedeutet Codezeile –

+0

Sie können die 'view.getId()' in einem Schalter nicht verwenden, da jeder Fall: einen Wert oder eine enum erfordert. wie 'case 1:' oder 'case ENUM_ITEM:' aber 'case R.id.myBtn:' ist eine Variable. Sie müssen also die Blockanweisung "if elseif" verwenden. Wenn Sie viele Widgets haben, haben Sie am Ende einen hässlichen 'if elseif'-Code. – Thupten

3

Ich habe gefunden mit Butterknife sorgt für sauberen Code. Und weil es Code-Generierung (keine Reflexionen) verwendet, hat es wenig Performance-Overhead.

public class ActivityMain extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     ButterKnife.inject(this); 
    } 

    @OnClick(R.id.button_foo) 
    void onFoodClicked() { 
    // Do some foo 
    } 

    @OnClick(R.id.button_bar) 
    void onBarClicked() { 
    // do some bar 
    } 
} 
+0

Ja, ich weiß schon davon, aber das ist nicht meine Frage –

+0

Offensichtlich bittet er nicht um irgendeine Art von Lib. – Nitesh

+0

Nicht der lib Kumpel. –

1

Für diesen speziellen Fall würde ich sagen, dass eine einzige Instanz eines OnClickListener ist der beste Ansatz für Sie. Sie haben eine "Has-a" -Beziehung und müssen nicht mehrere Instanzen erstellen, da Sie das Verhalten mit der Ansichts-ID im onClick(View view) Callback bearbeiten.

public class ActivityMain extends Activity implements View.OnClickListener { 

    private View.OnClickListener mClickListener = new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      switch (view.getId()) { 
       //handle multiple view click events 
      } 
     } 
    }; 

} 
2

Ihre ClickListener ist eine innere nicht-statische Klasse die Kopplung dieser ‚hat-a‘ ist nicht anders, als wenn Sie Ihre Klasse ActivityView.OnClickListener umgesetzt. Dies liegt daran, dass Ihre innere ClickListener eine Instanz von ActivityMain erfordert und wirklich nicht wiederverwendet werden kann. Ich würde argumentieren, dass Sie über Engineering sind und nicht wirklich etwas gewinnen.

EDIT: Um Ihre Frage zu beantworten Ich möchte anonym für jedes Widget View.OnClickListener haben. Ich denke, das schafft die beste Trennung der Logik. Ich habe auch Methoden wie setupHelloWorldTextView(TextView helloWorldTextView);, wo ich meine ganze Logik mit diesem Widget verbunden.

+0

mit einem separaten Listener für jedes Widget wäre wirklich eine traurige Umsetzung, und natürlich ist es nur meine Meinung :) –

+0

@SarthakMittal ist perfekt gerechtfertigt, Entkopplung Logik in einem separaten Listener-Objekt wird obligatorisch (in Bezug auf das Schreiben sauberer Code) vor allem wenn Sie Sie möchten wiederverwendbare Komponenten über Aktivitäten hinweg entwickeln, die dieselbe Click-Listener-Logik verwenden. Zeigen Sie einen einfachen Sortierdialog an, der in mehreren Aktivitäten verwendet wird. – humblerookie

2

Der erste Ansatz ist besser als der andere, weil View.OnClickListenerInterface statt abstract class ist. Außerdem kann das spätere Problem in verschiedenen Situationen auftreten, da Sie eine nicht statische innere Klasse verwenden.

+0

wärst du nett genug, um zu erklären, wie würde es lecken? und warum ist der erste Ansatz besser? –

+0

@SarthakMittal werfen Sie einen Blick auf diesen Artikel: http://blog.andresteingress.com/2011/10/12/anonymous-inner-classes-in-android/ –

5

Ich verwende button.setOnClickListener(this); wo meine Activityimplements View.OnClickListener, und dann erhalten Sie die ID der Button in einer separaten Methode. Im folgenden sehen Sie ein Beispiel:

public class MyActivity extends ActionBarActivity implements View.OnClickListener { 

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

     ... 

     Button myFirstButton = (Button) findViewById(R.id.YOUR_FIRST_BUTTON); 
     myFirstButton.setOnClickListener(this); 

     Button mySecondButton = (Button) findViewById(R.id.YOUR_SECOND_BUTTON); 
     mySecondButton.setOnClickListener(this); 

     ... 

    } 

    ... 

    @Override 
    public void onClick(View v) { 
     Button b = (Button) v; 
     switch(b.getId()) { 
      case R.id.YOUR_FIRST_BUTTON: 
       // Do something 
       break; 
      case R.id.YOUR_SECOND_BUTTON: 
       // Do something 
       break; 
      ... 
     } 
    } 

    ... 

} 
8

Zunächst einmal die Grundlagen hier lets get klar ..

durch eine Schnittstelle Implementierung Ihrer Klasse werden nicht, dass .. wie Sie gesagt haben:

"Unsere Aktivitätsunterklasse" ist - ein "ClickListener, der nicht vollständig wahr ist".

Ihre Klasse kann nur dann eine "Is-a" -Beziehung haben, in diesem Fall eine Activity. Die Implementierung einer Schnittstelle bedeutet, dass sie sich so verhalten kann, wie die Schnittstelle ihren Vertrag festgelegt hat.

Ein Beispiel:

Klasse Peter Mensch erstreckt .. bedeutet, Peter ist ein Mensch ..

Klasse Peter kann auch implementieren Programmierer, Musiker, Ehemann usw. bedeutet Peter wie oben verhalten können.

Wie für die beste Praxis, könnte man eine ganz eigene Klasse machen, die OnClickListener wie folgt implementiert:

class MyListener implements View.OnClickListener{ 

    @Override 
public void onClick(View view) { 
     // do whatever you want here based on the view being passed 
    } 

} 

Und in der Haupt Activity Sie MyListener instanziiert konnte und onClick() nennen und Ihre Sicht in es passieren:

+1

@Sarthak Mittal Haben Sie versucht Sharp Edge Ansatz vorgeschlagen, gefunden Probleme? Ich plane auch, meine Anwendungs-Hauptaktivitäts-Listener in separate Klassen zu verschieben, da meine Home-Aktivität auf 10 Aktionen reagiert (klicken, auswählen und andere). Auch Klassenlänge ist fast 4K Zeilen, schwer für neue Leute, um herauszufinden, wo sie sich ändern können. – vrs

+0

Ja das ist der springende Punkt, trennen Sie den Listener-Code in einer anderen Klasse, um leicht zu finden und Änderungen vorzunehmen. –

1

einfach Sie verwenden wie nicht implementiert Unterklasse oder nicht behandeln ein Klickereignis einfach so wie.

android.view.View.OnClickListener method_name = new android.view.View.OnClickListener() { 

     @Override 
     public void onClick(View v) { 
      // TODO Auto-generated method stub 
      // put your code . 
     } 
    }; 

und Griff Ereignis in Schaltfläche ya jede Art von Klickereignis wie

button_name.setOnClickListener(method_name); 

seine Arbeit sehr einfach Dank

+0

ja ich weiß, es funktioniert so, aber die Frage ist, was ist der beste Weg und warum? :) –

+0

@SarthakMittal ok Fine .. der beste Weg ist ein Onclicklistener zu implementieren und zu wechseln Fall und jede Schaltfläche, um Methode und Methode Aufruf bei switch-Anweisung zu tun. es ist sehr einfach und schön, ich folge diesem Weg in meiner ganzen Anwendung. Danke –

+0

wir alle machen das, das ist die gebräuchlichste Implementierung, bitte lies die Frage richtig und antworte dann. –

0

Es hängt wirklich von klicken, was Sie erreichen wollen. Wenn Sie z.B. eine komplexe Funktionalität mit Threading, Abhängigkeiten usw., ich persönlich mag es, sie komplett von der Aktivität in eine separate Klasse XyzAction zu entkoppeln, die die schweren Sachen macht, über gewisse Invoker s Bescheid weiß und sie bei Bedarf zurückgibt. Meine Invoker s sind im Grunde Objekte, die /OnTouch/etc implementieren. Listener s und binden sich an erforderliche Aktionen. Z.B.Es könnte eine LoginInvoker Implementierung OnClickListener für eine Button und eine ImageView und auch eine generische ActionListener, die aufgerufen wird, wenn eine MenuItem geklickt wird. Die Invoker verfügt über Update-Methoden zum Anzeigen des Fortschritts für den Benutzer und das Ergebnis der gebundenen Aktion. Die Aktion posten Aktualisierungen für ihre Invoker s und kann Garbage Collected sein, wenn alle von ihnen sterben, weil es keine Verbindung zur Benutzeroberfläche hat.

Für weniger komplexe Aktionen, ich Paar sie direkt an die Android-Komponente (d Activity/Feagment/View) und sie auch Actions nennen, mit dem großen Unterschied von ihnen die UI-Rückrufe direkt umzusetzen.

In beiden Fällen erkläre ich die Aktionen als Mitglieder, damit ich auf einen Blick sehen kann, welche spezifischen Aktionen die Android-Komponente unterstützt.

Wenn etwas so trivial ist wie "zeige einen Toast, wenn die Taste gedrückt wird", verwende ich anonyme innere Klassen für die Benutzeroberflächenrückrufe, weil Sie normalerweise nicht so viel an ihnen in Bezug auf Wartbarkeit kümmern.

4

Hier können Sie eine btnClickListner-Objekt erstellen und danach wird das nennst du btnCLickLisner Objekt, wenn überhaupt Sie möchten die onCLieck-Aktionen für Schaltflächen ausführen.

Lassen Sie uns annehmen, in meiner Tätigkeit habe ich eine 5 bis 10 Tasten und jede Taste separat zu schreiben onclick listner ist schlechte Idee. Um dies zu übertreffen, können wir wie folgt verwenden ..

registrieren Ihre Tasten

Button button1 = (Button)findViewById(R.id.button1); 
Button button2 = (Button)findViewById(R.id.button2); 
Button button3 = (Button)findViewById(R.id.button3); 
Button button4 = (Button)findViewById(R.id.button4); 
Button button5 = (Button)findViewById(R.id.button5); 

Hier bin ich Einstellung der Onclick listner auf meine Knöpfe nach Klick

button1.setOnClickListener(btnClickListner); 
button2.setOnClickListener(btnClickListner); 
button3.setOnClickListener(btnClickListner); 
button4.setOnClickListener(btnClickListner); 
button5.setOnClickListener(btnClickListner); 

Hier ist die btnClick Listner Implementierung

View.OnClickListener btnClickListner = new OnClickListener() 
    { 
    @Override 
     public void onClick(View v) 
     { 
      // TODO Auto-generated method stub 
      if(button1.getId() == v.getId()) 
      { 
       //Do Button1 click operations here 

      } 
      else if(button2.getId() == v.getId()) 
      { 

       // Do Button2 click operations here 

      } 
      else if(button3.getId() == v.getId()) 
      { 
       // Do Button3 click operations here 

      } 
      else if(button4.getId() == v.getId()) 
      { 
       // Do Button4 click operations here 

      } 
      else if(button5.getId() == v.getId()) 
      { 
       // Do Button5 click operations here 
      } 

     } 

    } 
0

Eine kleine Bemerkung dies und vielleicht ein bisschen Thema.

Was, wenn wir nicht nur OnClickListener implementieren und wir haben eine Reihe anderer Listener/Callback zu implementieren. In meiner Meinung wird es unordentlich werden, alle diese in der Klasse zu implementieren, anstatt anonyme Klassen/Lambda zu verwenden. Es ist schwer sich daran zu erinnern, welche Methode zu welcher Schnittstelle gehört.

Also wenn wir eine Schnittstelle (in diesem Fall OnClickListener) mehrere Male implementieren müssen, kann es eine gute Lösung sein, auf Klassenbasis zu implementieren und den Schalter/Fall zu verwenden.

Aber wenn wir mehrere Schnittstellen implementieren müssen kann es eine gute Lösung sein, anonyme Klassen zu verwenden/Lambda

Verwandte Themen