Подтвердить что ты не робот

Лучший способ реализовать 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" не предлагает каких-либо практических преимуществ и даже занимает больше памяти. Учитывая количество вложенных классов (и накладных расходов на память), которые мы будем создавать для каждого подобного слушателя, который мы реализуем, этот подход следует явно избегать.

4b9b3361

Ответ 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