Почему ListView.getCheckedItemPositions () не возвращает правильные значения? - PullRequest
27 голосов
/ 22 октября 2010

Приложение имеет ListView с включенным множественным выбором, в пользовательском интерфейсе оно работает как положено.Но когда я считываю значения с помощью этого кода:

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));
  }
}

я получаю этот вывод, независимо от того, в каком состоянии находится каждый флажок:

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

SparseBooleanArray кажется, возвращает false для любого несуществующего элемента, поэтому источником проблем, как представляется, является то, что getCheckedItemPositions () возвращает пустой массив.Метод ведет себя так, как будто в ListView нет элементов, но они есть.

Я могу видеть из документов, что никакие значения не возвращаются, когда ListView не настроен как множественный выбор, но это, используя это утверждение:

categorySelector.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

В моем сценарии адаптер, который я использую, является подклассом ArrayAdapter, и (без каких-либо веских доказательств) я подозреваю, что это может быть причиной, хотя я не могупонять, почему это не должно работать.

Ответы [ 15 ]

47 голосов
/ 03 августа 2011

kcoppock правильно, вам нужно использовать valueAt (), рабочий код должен быть

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");
        }
    }
}
6 голосов
/ 22 октября 2010

Я помню, что у меня была проблема с этим некоторое время назад. Здесь - мой предыдущий вопрос, который не имеет прямого отношения к вашей проблеме, но содержит некоторый код, который может помочь. Вы можете попробовать использовать checkedPositions.valueAt(int index) вместо checkedPositions.get(int index). Я думаю, что это может быть то, что вы на самом деле ищете.

4 голосов
/ 25 октября 2010

Я до сих пор не знаю, почему, но в моем сценарии getCheckedItemPositions() возвращает ложные значения для всех элементов. Я не вижу способа использовать методы ListView для получения логических значений. В объекте SparseBooleanArray, похоже, нет реальных данных. Я подозреваю, что это может быть из-за некоторой причуды моей реализации, возможно, из-за того, что я создал подкласс ArrayAdapter. Это расстраивает, такие проблемы, как реальная трата времени.

В любом случае, решение, которое я использовал, заключается в том, чтобы прикрепить обработчик к каждому флажку отдельно при создании строк ListView. Итак, с ListView.getView() я называю этот метод:

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
      }
  });
}
2 голосов
/ 01 января 2012

Это происходит, если вы не выбрали правильный ресурс для показа ваших различных предметов.Это прекрасно работает, если вы выберете встроенный ресурс android.R.layout.simple_list_item_multiple_choice.Метод getCheckedItemPositions каким-то образом связан со встроенным ресурсом.

1 голос
/ 15 октября 2014

Это старая ветка, но так как она в основном появилась первой в текущем поиске Google, вот быстрый способ понять, что делает listView.getCheckedItemPositions():

Если элемент списка вообще не был "переключен" в вашем ListView, он не будет добавлен в массив SparseBooleanArray, который возвращается listView.getCheckedItemPositions()

Но тогда вы действительно не хотите, чтобы ваши пользователи нажимали на каждый элемент списка, чтобы "правильно" добавить его в возвращенный SparseBooleanArray, верно?

Следовательно, для этого вам необходимо объединить использование valueAt () AND keyAt () для SparseBooleanArray.

    SparseBooleanArray checkedArray = listView.getCheckedItemPositions();

    ArrayList<DataEntry> entries = baseAdapter.getBackingArray(); //point this to the array of your custom adapter

    if (checkedArray != null)
    {
        for(int i = 0; i < checkedArray.size(); i++)
        {
            if(checkedArray.valueAt(i))    //valueAt() gets the boolean
                entries.yourMethodAtIndex(checkedArray.keyAt(i)); //keyAt() gets the key
        }
    }
1 голос
/ 05 декабря 2013

Нет необходимости обрабатывать проверку / снятие отметки с элементов в ListView. Он уже делает это самостоятельно.

То, что не выглядит документально, так это то, что ListView будет делать это только в том случае, если:

  1. a ListAdapter установлено и
  2. режим выбора: CHOICE_MODE_MULTIPLE и
  3. идентификаторы, используемые ListAdapter, являются стабильными .

Третий момент - это то, что на какое-то время сводило меня с ума.

Я не уверен, что означает «стабильный» (я думаю, что идентификаторы никогда не меняются, пока отображается список). Что касается ListView, это означает, что метод hasStableIds() в ListAdapter возвращает true.

Я создал простой подкласс ArrayAdapter, например:

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;
    }
}

(у вас уже есть свой подкласс, поэтому просто добавьте переопределение hasStableIds)

Конечно, нужно добавить конструктор, который использовался с ArrayAdapter.

Как только вы используете этот класс в качестве ListAdapter, getCheckedItemPositions() ведет себя как ожидалось.

Последнее замечание: setChoiceMode должен вызываться ПОСЛЕ настройки адаптера списка.

1 голос
/ 06 апреля 2011

Ни одно из перечисленных выше решений не сработало для меня, вместо этого я получаю каждый дочерний элемент (проверенный текст) из ListView и проверяю, отмечен он или нет:

0 голосов
/ 13 мая 2017

просто перейдите в xml, где определен ваш список, и установите свойство

**android:choiceMode="multipleChoice"**

мой 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>

и затем в вашем javafile как: -

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 голосов
/ 07 июня 2016
ArrayList<String> selectedChildren = new ArrayList<String>();

for(int i = 0;i<list.getChildCount();i++)
{
    CheckBox c = (CheckBox) list.getChildAt(i);
    if(c.isChecked())
    {
        String child = c.getText().toString();
        selectedChildren.add(child);
    }
}
Log.i(TAG, "onClick: " + selectedChildren.size());
0 голосов
/ 06 марта 2013
ArrayList<Integer> ar_CheckedList = new ArrayList<Integer>();

для каждого ячейки флажка, который я использую для хранения его в массиве

holder.chk_Allow.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if(isChecked)
                        ar_CheckedList.add(position);
                }
            });

при нажатии кнопки

for (int i = 0; i <  ar_CheckedList.size(); i++)
 {
        HashMap<String, String> temp=(HashMap<String, String>) contactList.get(ar_CheckedList.get(i));
        str_Phone_No=temp.get(TAG_CONTACT_MOBILE);
        send(str_Phone_No);
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...