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

La aplicación tiene un ListView con selección múltiple habilitada, 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 esta salida, sin importar en qué estado esté cada checkbox:

 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 falso para cualquier elemento inexistente, por lo que el origen de los problemas parece ser que getCheckedItemPositions () devuelve un conjunto vacío. El método se comporta como si no hubiera elementos en ListView, pero los hay.

Puedo ver en los documentos que no se devuelven valores cuando ListView no está configurado como selección múltiple, pero lo es, usando 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 esta 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 debería ser

 SparseBooleanArray checkedItems = categorySelector.getCheckedItemPositions(); if (checkedItems != null) { for (int i=0; i 

Recuerdo haber tenido un problema con esto hace un tiempo. Aquí está mi pregunta anterior, que no está directamente relacionada con su problema, pero contiene algunos códigos que pueden ser útiles. Lo que puede intentar es usar checkedPositions.valueAt(int index) lugar de checkedPositions.get(int index) . Creo que eso es lo que realmente estás buscando.

Todavía no sé por qué, pero en mi caso, getCheckedItemPositions() devuelve valores falsos para todos los artículos. No veo una forma de usar los métodos en ListView para obtener los valores booleanos. El objeto SparseBooleanArray parece no tener datos del mundo real. Sospecho que esto puede deberse a alguna peculiaridad de mi implementación, tal vez que he subclasificado ArrayAdapter. Es frustrante, problemas como este son una pérdida de tiempo real.

De todos modos, la solución que he usado es adjuntar un controlador a cada checkbox individualmente a medida que se crean las filas de ListView. 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 artículos. 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 integrado.

Ninguna de las soluciones anteriores me ha funcionado, en su lugar obtengo todos los elementos secundarios (un checkedTextView) de ListView y veo si están marcados o no:

  ListView myListView = myViewActivity.getListView(); ArrayList selectedChildren2 = new ArrayList(); for(int i = 0;i 

No es necesario controlar o desmarcar los elementos dentro de ListView. Ya lo hace por sí mismo.

Lo que no parece documentado es que ListView solo hará esto si:

  1. un ListAdapter está configurado y
  2. el modo de elección es CHOICE_MODE_MULTIPLE y
  3. los ids utilizados por el ListAdapter son estables .

El tercer punto fue lo que me volvió loco por un tiempo.

No estoy seguro de qué significa “estable” (supongo que los identificadores no cambian nunca mientras se muestra la lista). En lo que respecta al ListView, significa que el método hasStableIds() en ListAdapter devuelve verdadero.

ArrayAdapter una subclase simple de ArrayAdapter como esta:

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

(Ya tiene su subclase, así que simplemente agregue la anulación de hasStableIds )

Por supuesto, uno necesita agregar el constructor que se estaba utilizando con ArrayAdapter .

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

Una última nota: setChoiceMode debe llamarse DESPUÉS de configurar el adaptador de lista.

Este es un hilo viejo, pero dado que esto básicamente salió primero en la búsqueda actual de Google, aquí hay una manera rápida de entender lo que hace listView.getCheckedItemPositions() :

A menos que el elemento de la lista no se ‘alteró’ en absoluto en su ListView, no se agregará a SparseBooleanArray que es devuelto por listView.getCheckedItemPositions()

Pero entonces, ¿realmente no desea que sus usuarios hagan clic en cada elemento de la lista para agregarlo “correctamente” al SparseBooleanArray devuelto, ¿verdad?

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

  SparseBooleanArray checkedArray = listView.getCheckedItemPositions(); ArrayList 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 solucionó por mí. Cambie el método getView para que “int position” sea “final int position”. Luego haz esto con tu checkbox:

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

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

Déjame elaborar. lista es una referencia a la vista de lista y en mi caso el adaptador es una clase interna en el diálogo que contiene la lista.

Encontré este hilo teniendo el mismo problema, pero creo que he encontrado una solución alternativa que funcionó para mí por motivos desconocidos. Cada vez que intenté obtener un valor, no obtuve nada, pero si recorro la lista configurando todo en falso, comenzó a funcionar como estaba previsto.

Esta fue en realidad una función que había implementado en la que el usuario podía “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, solo cadenas.

 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” la lista

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!

aunque no creo que haya probado todas las variaciones descritas aquí, esta es la que me ha funcionado 🙂

  @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 encabezado que mi lista tiene en su lugar.

HTH

 ArrayList ar_CheckedList = new ArrayList(); 

por cada holer de checkbox que estoy usando para almacenarlo en matriz

 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 temp=(HashMap) contactList.get(ar_CheckedList.get(i)); str_Phone_No=temp.get(TAG_CONTACT_MOBILE); send(str_Phone_No); } 

¿No hay una diferencia bastante fundamental entre 'selected' y 'checked' ?

Sospeche que quiere setItemChecked() desde un OnItemSelectedListener

simplemente vaya al xml donde se define su lista de lista y establezca la propiedad

 **android:choiceMode="multipleChoice"** 

mi xmlfile

     

y luego en tu archivo java 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(); } } 
 ArrayList selectedChildren = new ArrayList(); for(int i = 0;i