¿Por qué ListView.getCheckedItemPositions () no devuelve valores correctos?

La aplicación tiene un ListView con selección múltiple activada, en la interfaz de usuario funciona como se esperaba. Pero cuando leo los valores usando este código:

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

Obtengo este resultado, sin importar el estado en el que se encuentre cada casilla de verificación:

 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 

El SparseBooleanArray parece devolver false para cualquier elemento inexistente, por lo que la fuente de los problemas parece ser que getCheckedItemPositions () está devolviendo una matriz vacía. El método se está comportando como si no hay elementos en ListView, pero hay.

Puedo ver desde los documentos que no se devuelven valores cuando el ListView no está configurado como multi-select, pero es, utilizando esta instrucción:

 categorySelector.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); 

En mi caso, el adaptador que estoy usando es una subclase de ArrayAdapter, y (sin ninguna evidencia sólida) sospecho que esto puede ser la causa, aunque no puedo ver por qué no debería funcionar.

Kcoppock tiene razón, necesita usar valueAt (), el código de trabajo debe ser

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

Recuerdo tener un problema con esto yo mismo un tiempo atrás. Esta es mi pregunta anterior, que no está directamente relacionada con su problema, pero contiene algún código que puede ayudar. Lo que quizás quiera probar es usar checkedPositions.valueAt(int index) lugar de checkedPositions.get(int index) . Creo que puede ser lo que realmente buscas.

Todavía no sé por qué, pero en mi escenario, getCheckedItemPositions() devuelve valores falsos para todos los elementos. No puedo ver una manera de utilizar los métodos en el ListView para obtener los valores booleanos. El objeto SparseBooleanArray parece no tener datos del mundo real en él. Sospecho que esto puede ser debido a algún capricho de mi implementación, tal vez que he subclasificado ArrayAdapter. Es frustrante, problemas como éste son un drenaje en tiempo real.

De todos modos, la solución que he utilizado es para adjuntar un controlador a cada Checkbox individualmente como filas ListView se crean. Así que desde ListView.getView() llamo a este método:

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

Sucede si no elige el recurso correcto para mostrar sus diferentes elementos. Funciona bien si elige el recurso integrado android.R.layout.simple_list_item_multiple_choice. El método getCheckedItemPositions está acoplado de alguna manera al recurso incorporado.

Ninguna de las soluciones anteriores ha funcionado para mí, en lugar de que cada niño (a checkedTextView) de la ListView y ver si está marcado o no:

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

No hay necesidad de manejar la comprobación / desconexión de elementos dentro de ListView. Ya lo hace por sí solo.

Lo que no parece documentado es que ListView sólo lo hará si:

  1. Se establece un ListAdapter y
  2. El modo de elección es CHOICE_MODE_MULTIPLE y
  3. Los identificadores utilizados por el ListAdapter son estables .

El tercer punto fue lo que me enloqueció durante un tiempo.

No estoy seguro de lo que significa 'estable' (supongo que los identificadores no cambian nunca mientras se muestra la lista). Por lo que se refiere a ListView, significa que el método hasStableIds() en ListAdapter devuelve true.

He creado una subclase sencilla de ArrayAdapter como esto:

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

(Usted ya tiene su subclase, por lo que sólo tiene que añadir el override hasStableIds )

Por supuesto, es necesario agregar el constructor que se estaba utilizando con ArrayAdapter .

Una vez que utilice esta clase como ListAdapter , getCheckedItemPositions() comporta como se esperaba.

Una última nota: setChoiceMode debe llamarse después de configurar el adaptador de lista.

Este es un hilo antiguo, pero ya que básicamente se presentó primero en la búsqueda actual de Google aquí es una manera rápida de entender lo que hace listView.getCheckedItemPositions() :

A menos que el elemento de la lista no estuviera "toggled" en su ListView, no se agregará al SparseBooleanArray que es devuelto por listView.getCheckedItemPositions()

Pero entonces, realmente no quieres que tus usuarios hagan clic en cada elemento de la lista para "correctamente" añadirlo a la SparseBooleanArray devuelto a la derecha?

Por lo tanto, es necesario combinar el uso de valueAt () AND keyAt () del SparseBooleanArray para esto.

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

Este ajuste lo arregló para mí. Cambie el método getView para que "int position" sea "final int position". A continuación, haga esto con su casilla de verificación:

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

                 Public void onCheckedChanged (CompoundButton buttonView, boolean isChecked) {
                     List.setItemChecked (posición, ((CheckBox) buttonView) .isChecked ());
                 }
             });

Permítanme elaborar. List es una referencia a la lista y en mi caso el adaptador es una clase interna en el cuadro de diálogo que contiene la lista.

Encontré este hilo teniendo el mismo problema pero pienso que he venido para arriba con una solución que trabajó para mí por razones unkown. Siempre que traté de obtener un valor que no tengo nada, pero si me bucle a través de la lista de configuración de todos los falsos que comenzó a funcionar como se pretende.

En realidad, esto era una característica que había implementado donde el usuario podía seleccionar "Seleccionar todo" o "Deseleccionar todo". Ejecuto este método en mi onCreate.

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

Ahora todos mis valores son correctos. Para obtener los valores, en mi caso, sólo Cuerdas.

 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 } 

Espero que esto ayude a alguien.

Yo también usé la solución que gyller sugiere que implica "iniciar" el listview

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

Antes de llamar a getCheckItemPositions (), y dejó de producir resultados erróneos!

Mientras que no creo que he intentado todas las variaciones descritas aquí, aquí es el que ha funcionado para mí 🙂

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

Y después

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

Estoy accediendo a la posición + 1 debido a una vista de cabecera que mi lista tiene en su lugar.

HTH

 ArrayList<Integer> ar_CheckedList = new ArrayList<Integer>(); 

Para cada holer de la casilla de verificación que estoy usando para almacenar en el array

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

Al hacer clic en el botón

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

¿No existe una diferencia fundamental entre 'selected' y 'checked' ?

Sospecha que desea setItemChecked() de un OnItemSelectedListener

ArrayList selectedChildren = new 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()); 

Simplemente vaya al xml donde está definido su listview y establezca la propiedad

 **android:choiceMode="multipleChoice"** 

Mi archivo xml

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

Y luego en su javafile como: –

 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(); } } 
  • Cómo ocultar la línea horizontal en la parte inferior de cada elemento en android listview?
  • Android: ListView selecciona el elemento y resalta el elemento seleccionado mediante programación
  • Capturando el evento TextChanged dentro de un ListView en Android
  • ¿Cómo establecer la posición fija para el botón de acción flotante por encima de listview muy larga en android?
  • Cómo pasar varios valores de matriz en una clase Adaptador personalizado para Vista de lista personalizada?
  • Listview dentro de listview y problema con height de la lista anidada listview
  • Ancho y color del borde del elemento ListView de Android
  • Android: ¿El menú contextual no aparece para ListView con los miembros definidos por LinearLayout?
  • Android listview desplazamiento a número de listitems
  • ¿Puedo insertar una columna en listview en tiempo de ejecución?
  • ¿Cómo obtener la vista de un elemento ListView?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.