29

I have problem with handling dynamically created Buttons on Android. I'm creating N buttons and I have to do the same method when button is clicked but I have to know which button is clicked.

for (int i = 0; i < NO_BUTTONS; i++){
        Button btn = new Button(this);
        btn.setId(2000+i);

        ...

        btn.setOnClickListener((OnClickListener) this);
        buttonList.addView(btn);
        list.add(btn);

Cucurrently I'm adding ID to every button and I'm using the method below to see which button was clicked. (line btn.setId(2000+i); and btn.setOnClickListener((OnClickListener) this);). This method is also implemented in the activity.

@Override
public void onClick(View v) {
    switch (v.getId()){
        case 2000: selectButton(0);
        break;

        ...

        case 2007: selectButton(7);
        break;
    }
 }

This doesn't look good to me so i'm asking is there some better way to do this? or how to send some information to onclick event? any suggestions?

Abdul Rahman
  • 2,097
  • 4
  • 28
  • 36
Ante
  • 8,567
  • 17
  • 58
  • 70

9 Answers9

64

You could create a method that returns an onclickListener and takes a button as a parameter. And then use that method to set the onClicklistener in the first loop you have..

Update: code could be soemthing along these lines:

View.OnClickListener getOnClickDoSomething(final Button button)  {
    return new View.OnClickListener() {
        public void onClick(View v) {
            button.setText("text now set.. ");    
        }
    };
}

as a method in the activity and then use it in the loop like this

button.setOnClickListener(getOnClickDoSomething(button));
Manfred Moser
  • 29,539
  • 13
  • 92
  • 123
  • yes, this is good if you develop a desktop app. But, we are talking about a mobile device which the memory is less. So, instead of using only one OnClickListener, you create 8 of it. that's a lot. Even though it is ugly, I would prefer the first approach and try to make the choice within a loop to make better. – Ömer Dec 20 '10 at 16:55
  • @Omer Are you sure Android does not optimize this on its own on compile? – blindstuff Dec 20 '10 at 19:59
  • 5
    I would suggest to implement clean, maintainable and readable code first and then optimize if you find performance problems. Not the other way around. Unless you numbers are crazy high I dont think it will matter noticably. And even if you notice a problem you could still optimise the method first .. e.g. to return listeners from a cache or so.. – Manfred Moser Dec 20 '10 at 20:33
12

I got one solution for this.. use this code in onCreate

linear = (LinearLayout) findViewById(R.id.linear);

LayoutParams param = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);

Button[] btn = new Button[num_array_name.length];
for (int i = 0; i < num_array_name.length; i++) {
    btn[i] = new Button(getApplicationContext());
    btn[i].setText(num_array_name[i].toString());
    btn[i].setTextColor(Color.parseColor("#000000"));
    btn[i].setTextSize(20);
    btn[i].setHeight(100);
    btn[i].setLayoutParams(param);
    btn[i].setPadding(15, 5, 15, 5);
    linear.addView(btn[i]);

    btn[i].setOnClickListener(handleOnClick(btn[i]));

}

after onCreate create one method of return type View.OnClickListener like this..

View.OnClickListener handleOnClick(final Button button) {
    return new View.OnClickListener() {
        public void onClick(View v) {
        }
    };
}
andrewsi
  • 10,807
  • 132
  • 35
  • 51
  • 1
    i found trouble while trying to create buttons dinamically inside a for loop, because i declared the onClick() method inside the loop. This way worked for me perfectly, as i saw that onClick() must be out of the loop. – iversoncru Mar 11 '15 at 09:41
5
Button.OnClickListener btnclick = new Button.OnClickListener(){

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub

        Button button = (Button)v;
    Toast.makeText(getApplicationContext(), button.getText().toString(),2).show();  
    }

};

call this listener by btn.setOnClickListener(btnclick);

Jon Lin
  • 142,182
  • 29
  • 220
  • 220
Vicky
  • 285
  • 2
  • 4
  • 13
3

View IDs should not be used for these purposes as View Ids are generated on compilation time depending on IDs defined in xml layout files.

Just place your own IDs in the setTag() method which is available at the View level (so Buttons inherit them). This "tag" can be anything that allow you to recognize a View from others. You retrieve its value with getTag().

Kevin Gaudin
  • 9,927
  • 3
  • 32
  • 34
  • i very much like the idea given here but found that since getTag() returns an "Object", even for simple tags that consist of integers (1,2,...) a constuct like `switch ( Integer.parseInt(v.getTag().toString()) ){ case 1: ...` seems necessary and might need additional try-catch handling that i don't see how to embed her in an elegant manner. the use of setId() as the OP proposed seems way less clean but a lot easier in comparison. any ideas on this? – antiplex Jan 25 '12 at 23:47
  • 1
    If you store the tag as Integer, simply typecasting to Integer is enough, you don't need to call the toString method and then parsing that as Integer. `(Integer) v.getTag()`. – Simon Forsberg Nov 03 '12 at 13:36
1

instead use setTag() function to distinct easily.

 for(int i=0;i<4;i++) {
     Button btn = new Button(this);
     btn.setTag(i);
     btn.setOnClickListener(new View.OnclickListener() {
         @Override
         public void onClick(View v) {
             int i=v.getTag();
             switch(i) {
                 case 1: btn.setText(i);
                     break;

                 case 2: btn.setText(i);
                     break;

                 case 3: btn.setText(i);
                     break;

                 case 4: btn.setText(i);
                     break;

                 default: btn.setText("Others");
             }
         }
     }
Anindya Dutta
  • 1,972
  • 2
  • 18
  • 33
0

Is preferable not to mess up with the ids, setTag and getTag methods were designed for that purpose, it's the fast and clean way to set a bunch of button listeners on a dynamic layout

This answer may you help: https://stackoverflow.com/a/5291891/2804001

Community
  • 1
  • 1
0
public class MainActivity extends Activity implements View.OnClickListener
{

LinearLayout linearLayout;
Button [] button;
View.OnClickListener listener;
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    linearLayout=(LinearLayout)findViewById(R.id.parent_lay);
    String[] array={"U123","U124","U125"};
    int length=array.length;
    System.out.println("11111111111111111111111111");
    button=new Button[length];
    for(int i=0;i<length;i++)
    {
        button[i]=new Button(getApplicationContext());
        button[i].setId(i);
        button[i].setText("User" + i);
        button[i].setOnClickListener(this);
        linearLayout.addView(button[i]);
    }
}
@Override
public void onClick(View view)
{
    view.getId();
    Button button=(Button)findViewById(view.getId());
    button.setText("Changed");
}
}
Newbee
  • 45
  • 1
  • 9
0

"This doesn't look good to me" why not? doesn't it work? You could also create a static member variable holding a list of all added buttons, and then look for the clicked button in that list instead.

fabio
  • 2,269
  • 5
  • 22
  • 34
  • i think that this breaks some principle or something.. i don't like switch statements.. i would like to while i'm adding OnClickListener pass some data/variable so i can later know which button was clicked.. is it possible? – Ante Dec 14 '10 at 00:44
  • @Ante B.: ok, could you do something like this on the onClick method: selectButton(v.getId()-2000); – fabio Dec 14 '10 at 18:10
  • or, you could also create a static variable called SelectedBtn, and then on the onClick method do something like: SelectedBtn = v; this way you can refer to that button which was clicked in other parts of your app - note that by doing this way could even avoid giving nesty Id's to your buttons. But i don't quite know what you're trying to do at all so i'm just giving shots here... – fabio Dec 14 '10 at 18:16
0

I don't know why you would want to create N buttons, it looks like your value of N is greater than 10 at least, if you are not trying to show them all at once (I mean fit all of them into one single screen, no scrolling) you could try to recycle the invisible buttons just like we do for list view using a list view holder. This would reduce your memory footprint and boost performance, and differentiate the buttons based either on the text you set on them or a tag or you can even hold a reference to those small number of buttons.

srinathhs
  • 1,998
  • 4
  • 19
  • 33
  • value of N is [4,16] and i'm trying to show them at once.. i use them to demonstrate sort algorithams.. – Ante Dec 20 '10 at 21:18