How to get Selected items from Multi Select List View
Asked Answered
S

13

51

I am using an array adapter and to this am adding an array list of string s , the list is multi select , How can i get the values of list items clicked ?

my_contacts_list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice,conts_list);
  my_contacts_list.setAdapter(adapter);

I was trying to do this ,

SparseBooleanArray positions = my_contacts_list.getCheckedItemPositions();
  int size=positions.size();
  int i=0;
  while(i <= size){
   conts_list.get(positions.get(i));
   i++;
  }

But position.get(i) is an array list , how to retrieve the selected items then ?

Skindive answered 4/1, 2011 at 5:15 Comment(2)
Are you using MultiAutoCompleteTextView?Parthenope
@Skindive check out this answer, it may help: https://mcmap.net/q/354627/-gmail-style-listviewReorganization
J
48

SparseBooleanArray.get returns a boolean, but I believe you need to check it for each position in your list, e.g.

int len = listView.getCount();
SparseBooleanArray checked = listView.getCheckedItemPositions();
for (int i = 0; i < len; i++)
 if (checked.get(i)) {
  String item = cont_list.get(i);
  /* do whatever you want with the checked item */
 }
Jedediah answered 4/1, 2011 at 5:25 Comment(3)
Tis answer is wrong, have you tried it ? or is it just wrong for me ?, in my case i only got 12 results the first seven were true and the rest false, the total items in my multi select list was 42, the key of the sparse boolean is what pointed to my list indexes, please mend your answer because it's marked as the correct answer i would hate for someone to fail because they followed a wrong answer, keep stack over flow clean ;)Cherub
I think the kicker in this example is knowing that cont_list is your original List fed to the adapter. Given that, I'm not sure how you can make this NOT work. checked.get(i), will only return TRUE, if the index, i is checked in the original List item passed as param to the adapter.Burbot
Thnks it work like a charm and we don't need to remove unchecked item. For loop automatically do it for us.Donaugh
L
46

This API is a mess. Here is what works for me.

SparseBooleanArray checked = tags.getCheckedItemPositions();
for (int i = 0; i < checked.size(); i++) {
    if(checked.valueAt(i)) {
        Tag tag = (Tag) tags.getItemAtPosition(checked.keyAt(i));
        Log.i("xxxx", i + " " + tag);
    }
}
Lackluster answered 22/12, 2011 at 2:15 Comment(5)
That doesn't work for me. Daren's solution work for me instead.Lethargic
how to select item on click item view element but not all item ? like in Solid ExplorerCertainly
For me, checked.size() always returns 0 and the values appear to reach 12 at first but with the correct key/value pairs. So I just use the getCount of the ListView to get the limit of the iteration and finish when I encounter an IndexOutOfBoudsException. Ugly as hell but so far it works.Ribaldry
Returns the set of checked items in the list. The result is only valid if the choice mode has not been set to CHOICE_MODE_NONE.Giule
what an unclear answer. don't get me wrong. i mean the language syntax.Cohlette
D
17

I believe the fastest way to get the info out of this SparseArray is to iterate over the keys (actually I'm fairly sure that the solutions above won't work in all cases). The ListView will enter a pair (index, true) into the SparseBooleanArray for every selected index.

So the code might look like this:

SparseBooleanArray checked = lv.getCheckedItemPositions();
int size = checked.size(); // number of name-value pairs in the array
for (int i = 0; i < size; i++) {
    int key = checked.keyAt(i);
    boolean value = checked.get(key);
    if (value)
        doSomethingWithSelectedIndex(key);
}
Dealate answered 13/9, 2012 at 12:36 Comment(1)
Works for me. This way of code is much readable than rest of others.Lethargic
C
4

I think the Answer from Daren Robbins is Wrong, here is my answer:

ArrayList<String> ids = extras.getStringArrayList("commonids");
SparseBooleanArray checked = lv.getCheckedItemPositions();
for (int i = 0; i < checked.size(); i++) {
    if(checked.get(i))
        Log.i("CheckedItem", ids.get(checked.indexOfKey(i)));
}

Assume ids is an arraylist with the same size of the listview containing the ids of the items in the list view

Cherub answered 4/12, 2011 at 11:0 Comment(0)
B
3

The thing is you must iterate all the list view items but not checkedPositions.

Define the variables:

  • listView (The instance of you ListView)
  • names (the ArrayList you are )
  • saveCheckedName (save all checked name to this Arraylist)

     SparseBooleanArray checkedPositions = listView.getCheckedItemPositions();
        for (int i = 0; i < subjectListView.getCount(); i++) {
                        if (checkedPositions.get(i) == true) {
                            saveCheckedName.add(names.get(i));
                        }
                    }
    
Boehmenist answered 26/9, 2012 at 21:51 Comment(0)
L
3

Like so many other things, multi-select ListViews are a real problem in Android.

Instead of simply requesting the selected items as a List of Objects (dear Google, this is what we expect):

List selected_items = my_list_view.getSelectedItems();

we are forced to use this stupendously ridiculous API:

SparseBooleanArray checked = my_list_view.getCheckedItemPositions();
    int num_selected = 0;
    for(int i = 0; i < checked.size(); i++) {
        if(checked.valueAt(i)) {
            num_selected++;
            int key = checked.keyAt(i);
            boolean value = checked.get(key);
            if (value) {
                //
            }
        }
    }

The horribly named SparseBooleanArray is populated by calling the even more horribly named getCheckedItemPositions() on the ListView. But instead of returning the positions of each selected/checked item in the list, it returns the position of every item in the list that WAS EVER touched, whether it is currently actually selected or not! Unbelievable, but true.

To calculate whether the item is ACTUALLY CURRENTLY checked, we are forced to test valueAt(i) for truthiness while looping through the 'was ever touched' array of items.

In addition to this madness, if we want to calculate the number of selected items, we appear to be forced to increment our own counter (e.g. num_selected).

With APIs like this one, it's little wonder developers are an angry lot!

Lake answered 26/1, 2016 at 17:15 Comment(0)
M
1

I think another option is to just keep track of all of this yourself.

    list.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> listView, View selectedItem,
                int position, long itemId) {
            //Keep a reference here, and toggle a global variable.
Mistrot answered 23/4, 2012 at 8:5 Comment(0)
T
1

HOW I SOLVED THE ISSUE with a second ArrayList :

  1. Created a second ArrayList instance
  2. Updated that ArrayList instance with the UNCHECKED items
  3. added it to the my listadapter

    public void removeSelectedItems(){
    
    updatedList = new ArrayList<String>(); //initialize the second ArrayList
    
    int count = lv.getCount();  //number of my ListView items
    SparseBooleanArray checkedItemPositions = getListView().getCheckedItemPositions();
    for (int i=0;i < count;i++){
        if(!checkedItemPositions.get(i))
    
        updatedList.add(liveNames.get(i)); //liveNames is the current ArrayList     
        Log.e("TEST", liveNames.get(i));
    }
    
    adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_multiple_choice, updatedList);
    
    setListAdapter(adapter);}
    

Hope it will be helpfull :)

Trouble answered 10/2, 2013 at 12:58 Comment(0)
B
1
Foo objectAtCheckedRow = null;
for (int i = 0; i < positions.size(); i++) { //positions.size() == 2
    objectAtCheckedRow = adapter.getItem(positions.keyAt(i));
    //Do something significant with object here
}

A couple things to understand

  • It's a key-value pair list.
  • The key is the index of a row, get it with positions.keyAt(i)
  • The value is whether the row at that index is checked or not(true or false), get it with positions.valueAt(i)
  • positions.get(i) returns the same boolean as .valueAt(i)
  • Careful not to get indexes mixed up. You do not need to(and should not) iterate over your whole list. Use int i to iterate over positions, but don't use i to get objects from your list
  • But in this specific case(listView.getCheckedPositions()) it only fills in true(checked rows), so you don't actually need to verify using .get(i) nor .valueAt(i)

Example: Let's say you've checked the 5th and 8th items in the list(index 4 and 7), then positions.size() == 2 and i will be 0 and then 1

So when:

i == 0 then keyAt(i) == 4

i == 1 then keyAt(i) == 7

i == 0 OR i == 1 then valueAt(i) == true AND get(i) == true

Beaded answered 24/5, 2013 at 6:0 Comment(0)
K
1

FYI, Here is how Google did it:

Excerpted from http://mytracks.googlecode.com/hg/MyTracks/src/com/google/android/apps/mytracks/util/Api11Adapter.java

/**
* Gets the checked positions in a list view.
* 
* @param list the list view
*/
private int[] getCheckedPositions(ListView list) {
    SparseBooleanArray positions  = list.getCheckedItemPositions();
    ArrayList<Integer> arrayList = new ArrayList<Integer>();
    for (int i = 0; i < positions.size(); i++) {
        int key = positions.keyAt(i);
        if (positions.valueAt(i)) {
            arrayList.add(key);
        }
    }
    int[] result = new int[arrayList.size()];
    for (int i = 0; i < arrayList.size(); i++) {
        result[i] = arrayList.get(i);
    }
    return result;
}

and here is my adapted version:

public static List<Integer> getAbsListViewCheckedItemPositions(AbsListView absListView) {
    SparseBooleanArray checked  = absListView.getCheckedItemPositions();
    List<Integer> positions = new ArrayList<>();
    int checkedSize = checked.size();
    for (int i = 0; i < checkedSize; i++) {
        if (checked.valueAt(i)) {
            positions.add(checked.keyAt(i));
        }
    }
    return positions;
}
Kizer answered 30/1, 2015 at 8:11 Comment(0)
Z
1

We use this in our Android utility class. The generics help prevent compiler warnings, but you can remove them if your adapter returns multiple types.

public static <T> Collection<T> getCheckedItems(ListView listView) {
        Collection<T> ret = new ArrayList();
        SparseBooleanArray checkedItemPositions = listView.getCheckedItemPositions();
        for (int i = 0; i < checkedItemPositions.size(); i++) {
            if (checkedItemPositions.valueAt(i)) {
                T item = (T) listView.getAdapter().getItem(checkedItemPositions.keyAt(i));
                ret.add(item);
            }
        }
        return ret;
}
Zippy answered 20/8, 2016 at 15:17 Comment(0)
F
1

Very simple, use below code

listViewRequests.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                    AppCompatCheckedTextView checkBox = (AppCompatCheckedTextView) view;

                    if (checkBox.isChecked() == true){
                        Log.i("CHECK",checkBox.isChecked()+""+checkBox.getText().toString());
                    }
                }
            });
Flashing answered 28/8, 2017 at 6:19 Comment(1)
Dude it was pretty good answer though. I used this technique in Xamarin.Android.Blackfoot
F
0
   for(int i =0; i< listView.getAdapter().getCount(); i++){
        if(listView.isItemChecked(i)){
            listView.getAdapter().getItem(i); // item
        }
    }

should be used after setAdapter() method

Floorman answered 30/6, 2020 at 11:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.