Подтвердить что ты не робот

Почему ListView.getCheckedItemPositions() не возвращает правильные значения?

В приложении есть 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 не настроен как multi-select, но он использует это утверждение:

categorySelector.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

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

4b9b3361

Ответ 1

Я все еще не знаю, почему, но в моем сценарии getCheckedItemPositions() возвращает значения false для всех элементов. Я не вижу способа использовать методы в 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

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

Что не задокументировано, так это то, что ListView будет делать это только в том случае, если:

  • a ListAdapter установлен и
  • Режим выбора: CHOICE_MODE_MULTIPLE и
  • Иды, используемые 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 необходимо вызвать ПОСЛЕ настройки адаптера списка.

Ответ 7

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

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

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

Следовательно, вам нужно объединить использование valueAt() И 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
        }
    }

Ответ 8

Нет ли принципиальной разницы между 'selected' и 'checked'?

Подождите, вы хотите setItemChecked() от OnItemSelectedListener...

Ответ 9

Эта настройка исправила это для меня. Измените метод getView так, чтобы "int position" было "окончательной int position". Затем сделайте это с помощью своего флажка:

((CheckBox) convertView).setOnCheckedChangeListener(new OnCheckedChangeListener() {

                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    list.setItemChecked(position, ((CheckBox) buttonView).isChecked());
                }
            });

Позвольте мне уточнить. list - это ссылка на список, и в моем случае адаптер является внутренним классом в диалоговом окне, содержащем список.

Ответ 10

Я нашел эту тему, имея ту же проблему, но я думаю, что придумал обходной путь, который работал у меня по неизвестным причинам. Всякий раз, когда я пытался получить значение, я ничего не получал, но если бы я пропустил список, установив все в false, он начал работать так же, как и предполагалось.

Это была функция, которую я реализовал, когда пользователь мог либо "Выбрать все", либо "Отменить выбор всех". Я запускаю этот метод в своем onCreate.

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

Теперь все мои значения верны. Для получения значений, в моем случае, просто строк.

private void importSelected() {     
    ListView lv = getListView();
    SparseBooleanArray selectedItems = lv.getCheckedItemPositions();

    for (int i = 0; i < selectedItems.size(); i++) {
        if (selectedItems.get(i)) {
            String item =  lv.getAdapter().getItem(selectedItems.keyAt(i)).toString();
        }
    }

    selectNone(); //Reset
}

Я надеюсь, что это поможет кому-то.

Ответ 11

Я тоже использовал решение gyller, которое предполагает "инициирование" списка

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

перед вызовом getCheckItemPositions(), и он прекратил выдавать ошибочные результаты!

Ответ 12

в то время как я не верю, что я пробовал все описанные здесь варианты, вот тот, который работал у меня:)

        @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());
                }
            });
...
       }

И позже

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

Я получаю доступ к позиции + 1 из-за заголовка, который имеет мой список.

НТН

Ответ 13

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

Ответ 14

Выбран ArrayListChildren = новый ArrayList();

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

Ответ 15

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

**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>

а затем в вашем 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();           

   }
}