I have a ListView in my Activity and for each row Im using my custom layout with a TextView and two Buttons. When I click any of these two buttons, I want a certain action to be performed. In my ArrayAdapter, in getView method, I set onClickListeners to these two buttons.
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
v = li.inflate(R.layout.process_row, null);
}
final Button processCheck = (Button) v.findViewById(R.id.processCheck);
processCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (process.isChecked() == false) {
process.setChecked(true);
processCheck.setBackgroundColor(Color.BLUE);
}
else {
process.setChecked(false);
processCheck.setBackgroundColor(Color.RED);
}
}
});
return v;
}
ArrayList holds objects of mz custom Class Process and process in the code is an instance of this class. So now when I click this button in one of the ListView rows, I would expect to change the boolean variable in the given Process instance and change the color of the button. That happens, but not only with this one row, but some 3-4 more. So after clicking, I have some 5 changed buttons instead of one. Do you know what im doing wrong here? Note that I dont know the ListActivity coding very well, most of the code is actually copied and edited a little bit from an example file. Thanks!
EDIT:
The problem is probably only with the layout somewhere. When I click the button, more of them change color but only the Process where i clicked has its boolean value changed.
edit: Find an “out of the box” example at the end of the post!
Because you see multiple rows affected I guess it has something to do how the system recycles resources and maybe the reference to the
Buttonis ambiguous.I’m not sure where I picked up this practise (either Android Tutorials or our former developer who learned android via these tutorials). However the suggestion is to use a nested class
ViewHolderPlace this in the Adapter or whatever class your
getView()is declared in and modify it as such:(I marked changes with $. I think this way they should be easy to spot if I use eclipse. Otherwise Find+Replace ^^)
So getTag() will return an Object associated with the view called on. Object is so incredible generic you can call it to the ViewHolder object you’ve created. Therefore you can reference the button and store it in the object.
Now whenever you get a ListView you can retrieve the Object and set the
OnclickListenerfresh and new. This way you’re only one Listener is called.Notice that you don’t have to call
v.setTag();again to “save” your changes.A pitfall might be if you do crazy stuff like inflating different layout in the same list for what reason ever. You might be tempted to assign different
ViewHandlersto them like:Then an unchecked call of
getView()to one ViewHolder or another will likely throw an error at runtime!