Android: як впоратися з натисканням кнопки


95

Маючи солідний досвід роботи в не-Java та не-Android областях, я вивчаю Android.

У мене багато плутанини з різними сферами, одна з них - це те, як обробляти натискання кнопок. Є щонайменше 4 способи зробити це (!!!), вони коротко перераховані тут

для узгодженості я перелічу їх:

  1. Запросіть члена View.OnClickListenerкласу в операції та призначте його екземпляру, який буде обробляти onClickлогіку в onCreateметоді діяльності.

  2. Створіть 'onClickListener' у методі діяльності 'onCreate' і призначте його кнопці за допомогою setOnClickListener

  3. Реалізуйте 'onClickListener' у самій діяльності та призначте 'this' як прослуховувач кнопки. У випадку, якщо в діяльності мало кнопок, слід проаналізувати ідентифікатор кнопки, щоб виконати обробник 'onClick' для відповідної кнопки

  4. Майте загальнодоступний метод для діяльності, що реалізує логіку 'onClick', і присвоюйте його кнопці в декларації xml про активність

Питання 1:

Це всі методи, чи є інший варіант? (Мені не потрібні інші, просто цікаво)

Для мене найбільш інтуїтивно зрозумілим способом буде найновіший: він вимагає введення найменшої кількості коду і є найбільш читабельним (принаймні для мене).

Хоча, я не бачу, щоб цей підхід широко застосовувався. Які мінуси для його використання?

Питання No2:

Які плюси / мінуси у кожного з цих методів? Будь ласка, поділіться своїм досвідом або хорошим посиланням.

Будь-який відгук вітається!

PS Я намагався пошукати в Google і знайти щось для цієї теми, але єдине, що я знайшов, це опис "як" це зробити, а не чому це добре чи погано.

Відповіді:


147

Запитання 1: На жаль, той, у якому ви говорите, є найбільш інтуїтивним, найменш використовується в Android. Як я розумію, вам слід розділити інтерфейс користувача (XML) та обчислювальну функціональність (файли класу Java). Це також полегшує налагодження. Насправді набагато легше читати таким чином і думати про Android imo.

Питання 2: Я вважаю, що в основному використовуються два - №2 та №3. Для прикладу я скористаюся кнопкою clickButton.

2

у формі анонімного класу.

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

Це мій улюблений, оскільки він має метод onClick поруч із тим, де змінна кнопки була встановлена ​​за допомогою findViewById. Здається, дуже акуратно і охайно, що тут знаходиться все, що стосується цього перегляду кнопки.

Монета, яку коментує мій колега, полягає в тому, що уявіть, що у вас багато поглядів, які потребують слухача onclick. Ви бачите, що ваш onCreate стане дуже довгим. Отже, чому він любить користуватися:

3

Скажімо, у вас є 5 кнопок:

Переконайтеся, що ваша активність / фрагмент реалізує 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
    }
}

Цей спосіб, як пояснює мій колега, є акуратнішим в його очах, оскільки всі обчислення onClick обробляються в одному місці і не переповнюють метод onCreate. Але недоліком я бачу те, що:

  1. погляди самі,
  2. а будь-який інший об’єкт, який може знаходитись у onCreate, що використовується методом onClick, повинен бути перетворений у поле.

Повідомте мене, якщо хочете отримати більше інформації. Я не відповів повністю на ваше запитання, оскільки це досить довге запитання. І якщо я знайду деякі сайти, я розширю відповідь, зараз я просто надаю певний досвід.


1
Для варіанту 2 ви захочете зробити це: clickButton.setOnClickListener (новий View.OnClickListener () {@Override public void onClick (View v) {// TODO, що ви хочете зробити}}); на допомогу у вирішенні OnClickListener
ColossalChris

Варіант 3, мабуть, найчистіший і найпростіший для розширення за допомогою шаблону MVP.
Raffaeu

Варіант 2 все ще може призвести до onCreate()того, що це не надто довго. Призначення слухача кліків та анонімні класи можуть бути розкладені на окремий допоміжний метод, який викликається onCreate().
Нік Алексєєв

@Colossal: Вам не потрібно це робити. Додайте розширення до класу активності, наприклад "реалізує View.OnClickListener".
TomeeNS

10

# 1 Я часто використовую останню, коли на макеті є кнопки, які не генеруються (але очевидно статичні).

Якщо ви використовуєте його на практиці та у комерційній програмі, зверніть тут додаткову увагу, тому що, коли ви використовуєте джерело обфускаторів, як ProGuard, вам потрібно буде позначити ці методи у своїй діяльності, щоб вони не були заплутаними.

Для архівування певного типу захисту часу компіляції за допомогою цього підходу подивіться на Android Lint ( приклад ).


№2 Плюси і мінуси для всіх методів майже однакові, і урок повинен бути таким:

Використовуйте те, що коли-небудь є найбільш підходящим або відчуває вас найбільш інтуїтивно зрозумілим.

Якщо вам потрібно призначити одне і те ж OnClickListenerдля кількох екземплярів кнопок, збережіть його у діапазоні класу (№1). Якщо вам потрібен простий слухач для кнопки, зробіть анонімну реалізацію:

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

Я, як правило, не впроваджую OnClickListenerв цю діяльність, це час від часу стає трохи заплутаним (особливо коли ви впроваджуєте кілька інших обробників подій, і ніхто не знає, що thisвсе робить).


Я стежу за тим самим, але все ще не отримую вихідних даних для функції, мій код і запит тут: stackoverflow.com/questions/25107427/…
Ракета

8

Я віддаю перевагу варіанту 4, але для мене це має інтуїтивний сенс, оскільки я занадто багато працюю в Grails, Groovy та JavaFX. "Чарівні" зв’язки між видом та контролером є загальними для всіх. Важливо добре назвати метод:

У поданні додайте метод onClick до кнопки або іншого віджета:

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

Потім у класі обробіть метод:

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

Знову ж таки, чітко назвіть метод, щось, що ви все одно повинні зробити, і обслуговування стає другим.

Одна велика перевага полягає в тому, що ви можете написати модульні тести вже зараз для цього методу. Варіант 1 може це зробити, але 2 і 3 складніше.


1
Я збираюся трохи вафельно запропонувати п’ятий варіант (ні, не в ролі Брюса Вілліса :)), варіант варіантів 2: використовуйте клас Presenter у фреймворці Model-View-Presenter для обробки кліків. Це робить автоматизоване тестування НАБАГАТО простішим. Перегляньте це посилання для отримання детальнішої інформації: codelabs.developers.google.com/codelabs/android-testing/…
Стів Гелман,

4

Найбільш вживаним способом є анонімне декларування

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

Також ви можете створити об'єкт View.OnClickListener і встановити для нього кнопку пізніше, але вам все одно потрібно перевизначити метод onClick, наприклад

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

Коли ваша діяльність реалізує інтерфейс OnClickListener, ви повинні замінити метод onClick (View v) на рівні активності. Тоді ви можете призначити цю діяльність як кнопку прослуховування, оскільки вона вже реалізує інтерфейс і замінює метод 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-й підхід, який використовується, коли кілька кнопок мають однаковий обробник, і ви можете оголосити один метод у класі активності та призначити цей метод декільком кнопкам у макеті xml, також ви можете створити один метод для однієї кнопки, але в цьому випадку я воліють оголошувати обробники всередині класу активності.


1

Варіанти 1 і 2 передбачають використання внутрішнього класу, який зробить код таким безладним. Варіант 2 якийсь брудний, тому що на кожну кнопку буде один слухач. Якщо у вас невелика кількість кнопок, це нормально. Для варіанту 4, я думаю, це буде важче налагодити, оскільки вам доведеться повернутися назад і четвертим кодом xml та Java. Я особисто використовую варіант 3, коли мені доводиться обробляти кілька натискань кнопки.


1

Мій зразок, протестований в Android Studio 2.1

Визначити кнопку в макеті xml

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

Виявлення пульсації 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

Щоб полегшити ситуацію, оскільки питання 2 зазначено, ви можете використовувати такий метод лямбда, щоб заощадити змінну пам’ять та уникнути навігації вгору та вниз у класі перегляду

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

але якщо ви хочете застосувати подію кліка до вашої кнопки відразу в методі.

Ви можете скористатись питанням 3 від @D. Тран відповідь. Але не забудьте реалізувати свій клас перегляду за допомогою View.OnClickListener.

В іншому - правильно використовувати Питання №3


1
Це слід вважати сучасною відповіддю у поєднанні з посиланнями на методи ІМО. Більшість інших відповідей не називають того факту, що вони є старими попередніми кодами Java8 на Android.
Ryan The Leach,

0

Питання №1 - це єдиний спосіб обробляти кліки перегляду.

Питання №2 -
Варіант №1 / Варіант №4 - Між варіантом №1 та варіантом №4 немає великої різниці. Єдина різниця, яку я бачу, полягає в тому, що в одному випадку діяльність - це реалізація OnClickListener, тоді як, в іншому випадку, це буде анонімне реалізація.

Варіант №2 - У цьому методі буде створено анонімний клас. Цей метод трохи обтяжливий, оскільки вам потрібно буде зробити це кілька разів, якщо у вас кілька кнопок. Для анонімних класів ви повинні бути обережними щодо усунення витоків пам’яті.

Варіант No3 - Хоча це простий спосіб. Зазвичай програмісти намагаються не використовувати будь-який метод, поки не напишуть його, і, отже, цей метод не використовується широко. Ви б бачили, що переважно люди використовують Варіант No4. Тому що він чистіший у термінах коду.


Привіт Гаураву, дякую за відповідь. Але чи можете ви пояснити, що ви тут маєте на увазі: для анонімних класів ви повинні бути обережними щодо усунення витоків пам'яті. Як тут виникають витоки пам’яті?
Будда

Ви просто повинні пам’ятати, що: якщо ви створюєте анонімний клас усередині методу, який може бути викликаний кілька разів протягом життя вашої програми, буде створено не кілька екземплярів одного класу, а кілька класів, включаючи їх екземпляри. Ви можете уникнути цього, використовуючи звичайні внутрішні класи та створюючи екземпляри слухачів як поля екземпляра. Спробуйте зменшити різні класи слухачів, повідомляючи стан слухача за допомогою аргументів конструктора. Регулярний внутрішній клас дає вам переваги спеціальних конструкторів та інших методів.
Risadinha

0

Існують також варіанти у вигляді різних бібліотек, які можуть зробити цей процес дуже звичним для людей, які використовували інші фреймворки MVVM.

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

Показує приклад офіційної бібліотеки, яка дозволяє прив’язувати кнопки таким чином:

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

0

Крок 1: Створіть 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>

Крок 2: Створіть 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!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.