0

I have a ListView that uses a custom layout that has 5 child View objects (4 TextView and 1 CheckBox) in the custom layout. Only the TextViews are bound, however - the CheckBox has no corresponding field in the database. The purpose of the CheckBox is simply to identify which of the items being displayed I would like to process in "the next step". I'm using a custom ViewBinder to assign the text values correctly (because some of the values from the DB are dates, etc).

Part of the user interface is three buttons - 'All', 'None', and 'Invert' that I use to toggle the status of each item in the list. For the 'All' button, for example, I do this with the following code (which I now know is NOT correct - I include it to show what I'm trying to do):

ListAdapter la = getListAdapter();
ListView lv = getListView();
int iCount = la.getCount();
for(int i=0; i<iCount; i++)
{
    View vv = lv.getChildAt(i);
    CheckBox cb = (CheckBox) vv.findViewById(R.id.ledgerItemCheckBox);
    cb.setChecked(true);
}

This works fine as long as the number of items in the list doesn't exceed the list size so that all items are always visible. When I exceed that number, though, the 'getChildAt' function sometimes returns null because (if I understand correctly) it isn't meant to return all of the items in the list, only those items that are visible, which results in a NullPointerException.

How can I properly set the CheckBox on all views, even if they aren't visible?

user
  • 86,916
  • 18
  • 197
  • 190
Michael Bray
  • 14,998
  • 7
  • 42
  • 68

1 Answers1

1

Create a pseudo binding to one of your TextView data, create an ArrayList of Boolean objects as your back end for the checkboxes. Please note an ArrayList may not be the best data structure for your application. Fill the ArrayList with booleans set to the initial value of the corresponding position of your Cursor's data set. When you're binding use the ArrayList as the back end data. When you select all, none, or invert, update the Boolean objects in the ArrayList then call notifyDataSetChanged() on your SimpleCursorAdapter.

Addition ah, the other half of the problem, yes, use the onClickListener for the CheckBoxes but use the same listener, don't create a new object for each. Use the getPositionForView() method to get your position and update the underlying data.

Dan S
  • 9,139
  • 3
  • 37
  • 48
  • accepting this answer because it definitely worked nicely! Thanks! Maybe you can give me a clue to the opposite question: When I click the checkbox on individual items, how do I detect that so I can update the backing boolean[]? Setting the ListView OnItemClickListener doesn't help. Maybe I have to set the onClickListener for every item as I'm setting the text in one of the fields? – Michael Bray Sep 11 '11 at 02:55
  • Works perfect! Interesting that getPositionForView works just fine when passing the CheckBox itself instead of the parent container (the real ListView item.) Also, I first tried this with OnCheckedChangedListener and had some real problems that didn't really make any sense... the listener was always called when I clicked 'None' but never when I clicked 'Invert' even though the code difference between the two is trivial (=false vs =!isChecked()). Not sure what was going on (maybe some recursive call junk) but once I switched to OnClickListener it worked great. thanks again! – Michael Bray Sep 11 '11 at 03:43