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

前端 未结 15 1870
北海茫月
北海茫月 2020-11-29 06:01

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.         


        
相关标签:
15条回答
  • 2020-11-29 06:25

    There is no need to handle the checking/unchecking of items within the ListView. It already does it on its own.

    What does not seem documented is that the ListView will only do this if:

    1. a ListAdapter is set and
    2. the choice mode is CHOICE_MODE_MULTIPLE and
    3. the ids used by the ListAdapter are stable.

    The third point was what drove me crazy for a while.

    I am not sure what 'stable' means (I guess that the ids don't ever change while the list is displayed). As far as the ListView is concerned, it means that the method hasStableIds() in ListAdapter returns true.

    I created a simple subclass of ArrayAdapter like this:

    public class StableArrayAdapter<T> extends ArrayAdapter<T> {
    
        public StableArrayAdapter(Context context, int textViewResourceId, List<T> objects) {
            super(context, textViewResourceId, objects);
        }
    
        @Override
        public boolean hasStableIds() {
            return true;
        }
    }
    

    (You already have your subclass, so just add the hasStableIds override)

    Of course, one needs to add the constructor that one was using with ArrayAdapter.

    Once you use this class as your ListAdapter, getCheckedItemPositions() behaves as expected.

    One last note: setChoiceMode must be called AFTER setting the list adapter.

    0 讨论(0)
  • 2020-11-29 06:27

    while I do not believe I have tried every variation described here, here is the one that has worked for me :)

            @Override
            public View getView(final int position, View convertView, ViewGroup parent) 
            {
    
                CheckedTextView retView = (CheckedTextView) convertView;
    ...
                retView.setOnClickListener(new View.OnClickListener() 
                {
                    public void onClick(View v)
                    {
                        CheckedTextView chkVw = (CheckedTextView) v; 
    //                  chkVw.toggle();
    //                  chkVw.setChecked(!chkVw.isChecked());
                        mLstVwWordingSets.setItemChecked(position + 1, !chkVw.isChecked());
                    }
                });
    ...
           }
    

    And later

            SparseBooleanArray checkedItemsArray = mLstVwWordingSets.getCheckedItemPositions();
            for (int i = 1; i <  mLstVwWordingSets.getCount(); i++)         //skip the header view
            {
                if (checkedItemsArray.get(i, false))
                    Log.d(_TAG, "checked item: " + i);
            }
    

    I am accessing position + 1 due to a header view that my list has in place.

    HTH

    0 讨论(0)
  • 2020-11-29 06:29

    I too used the solution gyller suggests that involves "initiating" the listview

    ListView lv = getListView(); for (int i = 0; i < lv.getCount(); i++) { lv.setItemChecked(i, false); }

    before calling getCheckItemPositions(), and it stopped producing erroneous results!

    0 讨论(0)
  • 2020-11-29 06:32

    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.

    0 讨论(0)
  • 2020-11-29 06:36

    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");
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 06:36

    simply go to the xml where your listview is defined and set property

    **android:choiceMode="multipleChoice"**
    

    my xmlfile

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.ali.myapplication.MainActivity">
    
        <ListView
            android:id="@+id/lvCustomList"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:choiceMode="multipleChoice"
            />
    
    </android.support.constraint.ConstraintLayout>
    

    and then in your javafile as:-

    SparseBooleanArray checked=lvDetail.getCheckedItemPositions();
    for (int i = 0; i < lvDetail.getAdapter().getCount(); i++) {
    if (checked.get(i)) {             
               Toast.makeText(getApplicationContext(),checked.get(i),Toast.LENGTH_SHORT).show();           
    
       }
    }
    
    0 讨论(0)
提交回复
热议问题