Лучшая практика для определения событий кнопок в Android - PullRequest
66 голосов
/ 16 июня 2011

У меня есть Layout, определенный в XML, который состоит из нескольких Button с.

В настоящее время я делаю это в методе OnCreate, чтобы определить обработчики событий для кнопок:

public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button newPicButton = (Button)findViewById(R.id.new_button);
    newPicButton.setOnClickListener(btnListener);
    ..... similarly for other buttons too
    .....
}

Внутри события Button onClick я запускаюкамера Intent для получения изображения и внутри обратного вызова onActivityResult Я снова устанавливаю обработчики событий вместе с настройкой View следующим образом:

protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{ 
    setContentView(R.layout.main);
    Button newPicButton = (Button)findViewById(R.id.new_button);
    newPicButton.setOnClickListener(btnListener);
    ...similarly for other buttons too
}

Я новичок в Android и этот подходпереопределение события каждый раз кажется мне довольно грязным.Я хотел бы знать, какова наилучшая практика с точки зрения определения обработчиков событий кнопок в подобных сценариях.

Редактирование: вставка моего полного класса

public class CameraAppActivity extends Activity 
{
    /** Called when the activity is first created. */

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

        Button newPicButton = (Button)findViewById(R.id.new_button);
        newPicButton.setOnClickListener(btnListener);
    }

    //---create an anonymous class to act as a button click listener---
    private OnClickListener btnListener = new OnClickListener()
    {

        public void onClick(View v)
        {   
             //Intent newPicIntent = new Intent(v.getContext(), NewPictureActivity.class);
             //startActivityForResult(newPicIntent, 0);
            Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(cameraIntent, 999);
        } 

    };  

    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    {  

        setContentView(R.layout.main);
        Button newPicButton = (Button)findViewById(R.id.new_button);
        newPicButton.setOnClickListener(btnListener);

       //if I comment last two lines nothing happens when I click on button

    }  

Основной вопрос заключается в

setContentView(R.layout.main);
Button newPicButton = (Button)findViewById(R.id.new_button);
newPicButton.setOnClickListener(btnListener);

Перерегистрация событий внутри onActivityResult .. это правильный подход?Или я что-то не так делаю?Потому что, если я не перерегистрирую событие, при нажатии кнопки ничего не происходит.

Ответы [ 10 ]

64 голосов
/ 16 июня 2011

Почему бы не зарегистрировать событие onClick в макете XML, а затем обработать его в коде. Вот как бы я это сделал:

<Button
android:id="@+id/my_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me"
android:onClick="onBtnClicked">
</Button>

и теперь создайте метод, который будет обрабатывать клики

public void onBtnClicked(View v){
    if(v.getId() == R.id.my_btn){
        //handle the click here
    }
}

В качестве альтернативы, вы можете установить OnClickListener индивидуально для каждого элемента в коде. Затем используйте операторы if / else или switch для определения источника.

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

UPDATE:
Хотя это правильный подход, я настоятельно рекомендую второй вариант. Его проще и легче поддерживать, особенно когда вы работаете с фрагментами.

39 голосов
/ 16 июня 2011

Вот лучший подход с кодом:

  public class MyTest extends Activity implements OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     //... some other code here to init the layout
        Button btn1 = (Button)findViewById(R.id.button1);
        Button btn2 = (Button)findViewById(R.id.button2);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.button1:
                break;
            case R.id.button2:
                break;
        }
    }
}

Новый класс с интерфейсом хорош только в том случае, если вы хотите отделить реализацию (когда вы хотите использовать тот же код класса в другом месте, переместитеэто к другому отдельному файлу класса и т. д.), но в целом, если вы делаете вещи, связанные с текущей активностью, на которой вы работаете, и реализации onClick зависят от того, выполняется ли она со ссылкой на определенные там объекты, вам определенно следует использовать предложенный мной метод.

Создание интерфейсов классов полезно только в том случае, если вы хотите установить связь между отдельными классами или действиями и разделить вещи.кроме этого, это плохая практика создания подклассов для этого.

12 голосов
/ 03 апреля 2012

это лучший подход

@Override
public void onCreate(Bundle savedInstanceState) {
        button1.setOnClickListener(onClickListener);
        button2.setOnClickListener(onClickListener);
        button3.setOnClickListener(onClickListener);
}

private OnClickListener onClickListener = new OnClickListener() {
     @Override
     public void onClick(final View v) {
         switch(v.getId()){
             case R.id.button1:
                  //DO something
             break;
             case R.id.button2:
                  //DO something
             break;
             case R.id.button3:
                  //DO something
             break;
         }

   }
};
8 голосов
/ 16 июня 2011

Наилучшая практика не определена. Это сильно зависит от варианта использования. Вы можете определить их в своем XML-макете, используя атрибут Button * onClick.

Пример XML:

<!-- Stuff -->
<Button android:id="@+id/my_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click Me!"
    android:onClick="myClickMethod" />

Пример Java:

// stuff
public void myClickMethod(View v) {
    // more stuff
}

Таким образом, вам не нужно реализовывать OnClickListener самостоятельно. Вы можете назначить каждой кнопке один и тот же метод onClick, а затем просто решить для каждого представления, какое действие следует инициировать, или вы можете иметь отдельный метод для каждой кнопки.

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

7 голосов
/ 17 декабря 2014

Мне нравится "современный" способ DI с использованием Нож для масла :

  1. Объявите ваше мнение
@InjectView(R.id.buttonAlert) 
Button buttonAlert;
  1. Внедрить все аннотированные ресурсы
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.inject(this);
 }
  1. Аннотируйте и реализуйте свой метод onClick
@OnClick(R.id.buttonAlert)
public void alertClicked(View v){
    // your logic
}
2 голосов
/ 16 июня 2011

@ Хасан Это лучший подход, который я нашел и который работает для меня каждый раз безупречно.

  • В Layout.xml определите onClick для кнопки

                    <Button android:id="@+id/Button01"          
                        android:onClick="@string/method" 
                        android:focusable="true" android:clickable="true"
                        ">
                    </Button>
    
  • В файле R.string добавьте следующую строку

string name = "method"> buttonFunction

  • В файле sample.java функция, определенная в R.string, будет вызываться при нажатии кнопки и должна выглядеть примерно так:

    public void buttonFunction (View view) { // делаем сетку как на нажатие кнопки }

0 голосов
/ 15 сентября 2016

Вот как я это сделал:

  1. В XML-файле «Кнопки» установите android: onClick = «onClick».
  2. В своей деятельности реализуйте View.OnClickListener.
  3. Внутри метода onClick используйте клавишу Switch (как показано ниже).

@ Override

public void onClick(View view) {
    Intent intent;
    switch(view.getId()){

        case R.id.home_button:
            //DO something
            intent = new Intent(HashTagActivity.this,MainActivity.class);
            startActivity(intent);
            break;
        case R.id.back_button:
            //DO something
             intent = new Intent(HashTagActivity.this,ClassActivity.class);
            startActivity(intent);
            break;
        case R.id.favorite_button:
            //DO something
            break;
        case R.id.copy_button:
            //DO something

            break;

    }
}

Отлично работает.

0 голосов
/ 30 января 2014

Я знаю, что это старое, но если кому-то интересно, почему вы не можете добавить onClickListener из onActivityResult, то есть потому, что кнопка пуста.Если вы инициализируете его еще раз (так же, как в onCreate), вы можете добавить слушателя.Будьте осторожны, однако, все остальное также будет нулевым, так что, если вы берете данные из EditText, например, вы должны также инициализировать это (простая проверка, если объект равен нулю в lisneter, сделаеттрюк).

0 голосов
/ 16 июня 2011

Проблема в том, что объект для кнопки newPicButton создается как локальный объект, действительный только в области действия функции onCreate, и как только код завершает работу этой функции, сборщик мусора освобождает объект для кнопки. вам нужно объявить объект newPicButton вне любого метода, а затем в методе onCreate назначить ему слушателя. Это решит вашу проблему, и я надеюсь, что объяснил, почему ничего не происходит, когда вы удаляете код для newPicButton в методе onActivityResult:)

0 голосов
/ 16 июня 2011

Ваша активность должна реализовывать OnClickListener, и вы должны написать всю свою обработку событий для всех кнопок внутри одного метода OnCLick ().

...