Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is ListView.getCheckedItemPositions() not returning correct values?

The app has a ListView with multiple-selection enabled, in the UI it works as expected. But when I read the values out using this code:

Log.i(TAG,"Entered SearchActivity.saveCategoryChoice()");
SparseBooleanArray checkedPositions = categorySelector.getCheckedItemPositions();
Log.i(TAG,"checkedPositions: " + checkedPositions.size());

if (checkedPositions != null) {
  int count = categoriesAdapter.getCount();
  for ( int i=0;i<count;i++) {
    Log.i(TAG,"Selected items: " + checkedPositions.get(i));
  }
}

I get this output, no matter what state each checkbox is in:

Entered SearchActivity.saveCategoryChoice()
checkedPositions: 0
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false

The SparseBooleanArray seems to return false for any non-existent item, so the source of the problems seems to be that getCheckedItemPositions() is returning an empty array. The method is behaving as if there are no items in the ListView, but there are.

I can see from the docs that no values are returned when the ListView is not set up as multi-select, but it is, using this statement:

categorySelector.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

In my scenario, the adapter I'm using is a subclass of ArrayAdapter, and (without any solid evidence) I suspect this may be the cause, though I can't see why it shouldn't work.

like image 641
Ollie C Avatar asked Oct 22 '10 12:10

Ollie C


4 Answers

kcoppock is right, you need to use valueAt(), the working code should be

SparseBooleanArray checkedItems = categorySelector.getCheckedItemPositions();
if (checkedItems != null) {
    for (int i=0; i<checkedItems.size(); i++) {
        if (checkedItems.valueAt(i)) {
            String item = categorySelector.getAdapter().getItem(
                                  checkedItems.keyAt(i)).toString();
            Log.i(TAG,item + " was selected");
        }
    }
}
like image 105
buergi Avatar answered Oct 19 '22 20:10

buergi


I remember having an issue with this myself a while back. Here is my previous question, which isn't directly related to your issue, but contains some code that may help. What you might want to try is using checkedPositions.valueAt(int index) rather than checkedPositions.get(int index). I think that may be what you're actually looking for.

like image 32
Kevin Coppock Avatar answered Oct 19 '22 21:10

Kevin Coppock


I still do not know why, but in my scenario, getCheckedItemPositions() returns false values for all items. I cannot see a way to use the methods on the ListView to get the boolean values out. The SparseBooleanArray object seems to have no real-world data in it. I suspect this may be because of some quirk of my implementation, perhaps that I've subclassed ArrayAdapter. It's frustrating, issues like this are a real time-drain.

Anyway, the solution I have used is to to attach a handler to each Checkbox individually as ListView rows are created. So from ListView.getView() I call this method:

private void addClickHandlerToCheckBox(CheckBox checkbox) {
  checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
      public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
        CheckBox checkbox = (CheckBox)arg0; 
        boolean isChecked = checkbox.isChecked();
        // Store the boolean value somewhere durable
      }
  });
}
like image 4
Ollie C Avatar answered Oct 19 '22 21:10

Ollie C


None of the above solutions have worked for me, instead I get every child (a checkedTextView) from the ListView and see if it is checked or not:

            ListView myListView = myViewActivity.getListView();
        ArrayList<String> selectedChildren2 = new ArrayList<String>();

        for(int i = 0;i<myListView.getChildCount();i++)
        {
            CheckedTextView c = (CheckedTextView) myListView.getChildAt(i);
            if(c.isChecked())
            {
                String child = c.getText().toString();
                selectedChildren.add(child);
                }
        }
like image 2
notBanana Avatar answered Oct 19 '22 20:10

notBanana