Best practice for defining button events in android


Answers

Here is the best approach with code:

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

The new class with an interface is only good if you want to decouple the implementation (when you want to use the same class code somewhere else, move it to another seperate class file etc..) but in general if you are doing things connected with the current activity you are on and the onClick implementations depend on it running with reference to the objects defined there you should definitely use the method i suggested.

Creating class interfaces is only good when you want to achieve communication between seperate classes or activities and keep things apart. other than that its a bad practice creating subclasses for this.

Question

I have a Layout defined in XML which consists of several Buttons.

Currently I am doing this in the OnCreate method to define the event handlers against the buttons:

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

Inside of the Button's onClick event, I launch a camera Intent to get a picture and inside the onActivityResult callback I am again setting the event handlers along with setting the View like this:

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
}

I am new to android and this approach of redefining an event every time seems quite dirty to me. I would like to know what is the best practice in terms of defining button event handlers in scenarios like this.

Edit: pasting my complete class

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

    }  

The main question is

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

Re-registering events inside onActivityResult.. is it right approach? Or am I doing something wrong? Because If I don't re-register event nothing happens when I click the button.




Android one OnClick method for multiple buttons?

If you want to reduce the coding lines then use View's OnClick() with switch statement and if you want to handle separately all click (for easily understanding and maintaining code) then use separate all button's onClick().

Update:

If you have declared Buttons in your Activity layout xml file, than write attribute android:onClick="" with same method name for all buttons and implement that method in your activity. Now you have one method for all buttons and in that method differentiate buttons with id.

Example:

<?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/button1"
            android:layout_width="wrap_content"
            android:onClick="buttonOnClick"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button 1" />
    <Button android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:onClick="buttonOnClick"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button 2" />
    <Button android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:onClick="buttonOnClick"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button 3" />
</LinearLayout>

Now in your Activity implement buttonOnClick like,

public void buttonOnClick(View view)
{
 switch(view.getId())
 {
  case R.id.button1:
  // Code for button 1 click
  break;

  case R.id.button2:
  // Code for button 2 click
  break;

  case R.id.button3:
  // Code for button 3 click
  break;
 }
}

Or you can apply same switch case for dynamically added buttons in your activity, like instead of buttonOnClick you have to use implemented View's OnClickListerner's onClick.




best implementation of onclick()

In that case, I might add implements View.OnClickListener to the activity class, and then make a single onClick that looks like:

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

This only really makes sense if the actions of all those buttons are somehow related, and if they are then it can significantly reduce code duplication. You would still have to do view.setOnClickListener(this) for each one, too.

Alternatively, if you want you can remove the implements View.OnClickListener and the @Override and simply register your method in the XML, like Kevin said. That would allow you to have multiple of these "grouped" click listeners.




You can use the xml attribute onClick:

<?xml version="1.0" encoding="utf-8"?>
<!-- layout elements -->
<Button android:id="@+id/mybutton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click me!"
    android:onClick="myFancyMethod" />
<!-- even more layout elements -->

More Information




I prefer using the following solution for handling onClick events. This works for Activity and Fragments as well.

public class StartFragment extends Fragment implements OnClickListener{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.fragment_start, container, false);

        Button b = (Button) v.findViewById(R.id.StartButton);
        b.setOnClickListener(this);
        return v;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.StartButton:

            ...

            break;
        }
    }
}



this.btnAddFriedtoFacebook = (Button) this.findViewById(R.id.btnAddFriedtoFacebook);
this.btnAddFriedtoFacebook.setOnClickListener(this.backButtonClickListener);

public OnClickListener backButtonClickListener = new OnClickListener()
{
public void onClick(final View view)
{
   if (view == MatchInfoActivity.this.btnBack)
    {
        MatchInfoActivity.this.finish();
    }
    if( view == MatchInfoActivity.this.btnAddFried){
       Intent i = new Intent(Intent.ACTION_VIEW);
       MatchInfoActivity.this.startActivity(i);
    }
    if( view == MatchInfoActivity.this.btnAddBuddy){
       Intent i = new Intent(Intent.ACTION_VIEW);
       MatchInfoActivity.this.startActivity(i);
    }
}
};

Here is the good way.