Лучший способ реализовать View.OnClickListener в android

Предположим, что у нас есть Activity с большим количеством представлений, на которые должен регистрироваться OnClickListener.

Наиболее распространенным способом реализации этого является включение подкласса Activity-Subclass в OnClickListener, что-то вроде этого:

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

Способ, которым я его реализую, - создать частный класс внутри подкласса Activity и позволить этому внутреннему классу реализовать OnClickListener:

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

Таким образом, код выглядит более организованным и простым в обслуживании.

Более того, говоря о связях "Is-a", "Has-a", последнее кажется хорошей практикой, потому что теперь Activity-Subclass будет иметь отношение "Has-a" с ClickListener. Хотя в первом методе мы хотели бы сказать, что "Наша активность-подкласс" Is-a "ClickListener, что не совсем верно.

Обратите внимание, что я не занимаюсь служебными данными памяти, которые вызвали бы последнее.

Кроме того, добавление тега onClick в xml полностью исключается.

Итак, что на самом деле является лучшим способом реализации ClickListener?

Пожалуйста, не предлагайте такие библиотеки, как RoboGuice или ButterKnife и т.д.

UPDATE:

Я хотел бы поделиться подходом, который я наконец принял.

Я непосредственно реализую слушателя в Activity/Fragment.

Что касается дизайна ООП. Подход "HAS-A" не предлагает каких-либо практических преимуществ и даже занимает больше памяти. Учитывая количество вложенных классов (и накладных расходов на память), которые мы будем создавать для каждого подобного слушателя, который мы реализуем, этот подход следует явно избегать.

Ответ 1

Во-первых, нет никакой лучшей практики, определяемой Android относительно регистрации прослушивателей кликов. Это полностью зависит от вашего варианта использования.

Реализация интерфейса View.OnClickListener для Activity - это путь. Поскольку Android настоятельно рекомендует реализацию интерфейса снова и снова, является ли это Activity или Fragment.

Теперь, как вы описали:

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

Это ваш подход. Теперь это ваш способ реализации, и в этом нет ничего плохого, если вы не беспокоитесь о нехватке памяти. Но какая польза от создания внутреннего класса и реализации View.OnClickListener, если вы можете просто реализовать это в основном классе, что также может привести к ясности и простоте кода, которые вам нужны.

Итак, это просто обсуждение, позволяющее получить наилучшее возможное решение для реализации View.OnClickListener, потому что если вы пойдете с практической точки зрения для всех, вы пойдете на решение, которое просто и эффективно с точки зрения памяти.

Поэтому я предпочел бы обычный способ. Это делает вещи простыми и эффективными. Проверьте код ниже:

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

P.S: Ваш подход, безусловно, увеличит количество строк кода: P;)

Ответ 2

Прежде всего, давайте выясним основные принципы.

Используя интерфейс, ваш класс не станет таким.. как вы сказали:

"Наша подкласс" Activity-Subclass "Is-a" ClickListener, что не совсем верно ".

У вашего класса может быть только отношение "Is-a", если оно расширяется, в этом случае Activity. Внедрение интерфейса означает, что он может вести себя так же, как интерфейс устанавливает свой контракт.

Пример:

класс Питер расширяет Человека.. означает, что Питер - человек.

класс Питер может также реализовать программиста, музыканта, мужа и т.д. означает, что Питер может вести себя как выше.

Что касается лучшей практики, вы можете сделать совершенно отдельный класс, который реализует OnClickListener следующим образом:

class MyListener implements View.OnClickListener{

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

}

И в вашем основном Activity вы можете создать экземпляр MyListener и вызвать onClick() и передать в нем свое представление:

MyListener listener = new MyListener();

Button b = null;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    button = (Button)findViewById(R.id.button);
    listener.onClick(button);
   }

Ответ 3

Я использую button.setOnClickListener(this);, где my Activity implements View.OnClickListener, а затем получает идентификатор Button в отдельном методе. Ниже приведен пример:

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;
            ...
        }
    }

    ...

}

Ответ 4

Здесь вы можете создать объект btnClickListner, после чего вы вызовете этот объект btnCLickLisner, когда захотите выполнить действия onCLieck для кнопок.

Предположим, что в моей деятельности у меня есть кнопки от 5 до 10 и запись каждой кнопки, отдельный onclick listner - плохая идея. Чтобы это произошло, мы можем использовать, как показано ниже.

зарегистрируйте свои кнопки

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

Здесь я устанавливаю onclick listner на мои кнопки после нажатия

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

Вот реализация btnClick Listner

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
            }

        }

     }

Ответ 5

Я нашел использование Butterknife для чистого кода. И поскольку он использует генерацию кода (а не отражения), он имеет небольшие накладные расходы.

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

Ответ 6

Ваш ClickListener - это внутренний нестатический класс, связанный с этим "has-a" не отличается от того, если ваш класс Activity реализован View.OnClickListener. Это связано с тем, что ваш внутренний ClickListener требует экземпляра ActivityMain и действительно не может быть повторно использован. Я бы сказал, что вы закончили инженерное дело и на самом деле ничего не набираете.

EDIT: для ответа на ваш вопрос мне нравится анонимный View.OnClickListener для каждого виджета. Я думаю, что это создает лучшее разделение логики. У меня также есть методы вроде setupHelloWorldTextView(TextView helloWorldTextView);, где я поместил всю свою логику, связанную с этим виджетами.

Ответ 7

Первый подход лучше, чем другой, потому что поэтому View.OnClickListener является Interface вместо abstract class. кроме того, позже может произойти утечка в различных ситуациях, так как вы используете нестатический внутренний класс.

Ответ 8

В этом конкретном случае я бы сказал, что поддерживать единственный экземпляр OnClickListener - лучший подход для вас. У вас будет отношение "Has-a", и вам не нужно будет создавать несколько экземпляров, так как вы обрабатываете поведение, используя идентификатор вида в обратном вызове onClick(View view).

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

}

Ответ 9

просто вы используете, как не реализуете подкласс или не обрабатываете событие click, просто делайте это так.

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 .
        }
    };

и обрабатывать событие click в кнопку ya любой тип события click, например

button_name.setOnClickListener(method_name);

его работа очень просто Благодаря

Ответ 10

Это действительно зависит от того, чего вы хотите достичь. Если у вас есть, например, сложная функциональность с потоками, зависимостями и т.д., мне лично нравится полностью отделить ее от Activity в отдельный класс XyzAction, который делает тяжелый материал, знает о некотором Invoker и возвращает их результаты, если это необходимо. Мой Invoker - это в основном объекты, которые реализуют OnClick/OnTouch/etc. Listener и связывают себя с необходимыми действиями. Например. может существовать LoginInvoker реализация OnClickListener для Button и ImageView, а также общий ActionListener, который вызывается при нажатии MenuItem. Invoker имеет методы обновления для отображения прогресса пользователю и результата связанного действия. Сообщения о действиях обновляются до Invoker и могут быть собраны в мусор, если все они умирают, потому что у него нет связи с пользовательским интерфейсом.

Для менее сложных действий я связываю их непосредственно с компонентом Android (т.е. Activity/Feagment/View), а также вызывается их Actions, причем большая разница в них напрямую связана с обратными вызовами пользовательского интерфейса.

В обоих случаях я объявляю действия как члены, поэтому я быстро вижу, какие конкретные действия поддерживает компонент Android.

Если есть что-то тривиальное, например, "показать кнопку Toast, если нажата кнопка", я использую анонимные внутренние классы для обратных вызовов пользовательского интерфейса, потому что вам, как правило, почти ничего не стоит в отношении ремонтопригодности.

Ответ 11

Небольшое замечание к этому и, возможно, немного темы.

Что, если мы не просто реализуем OnClickListener, и у нас есть куча других Listeners/Callback для реализации. В моем мнении он станет беспорядочным, чтобы реализовать все это в классе вместо использования анонимных классов /lambda. Трудно вспомнить, какой метод принадлежит к интерфейсу.

Итак, если нам нужно реализовать интерфейс (в данном случае OnClickListener) несколько раз, это будет хорошим решением для реализации на базе классов и с помощью переключателя /case.

Но если нам нужно реализовать несколько интерфейсов, это может быть хорошим решением для использования анонимных классов/lambda