0

My app has an SparseBooleanArray to store selected entries in a ListAdapter. The array is initialized as empty in the constructor.

private SparseBooleanArray mSelectedItemsIds;

public TaskArrayAdapter(@NonNull Context context, @NonNull List<Task> objects) {
    super(context, R.layout.item_task, objects);
    mSelectedItemsIds = new SparseBooleanArray();
    Log.d("Booleansize", String.valueOf(mSelectedItemsIds.size()));
}

Now in the getView method I check, whether the current position is in the array or not:

if (mSelectedItemsIds.valueAt(position)) {
        convertView.setBackgroundColor(Color.BLUE);
        convertView.getBackground().setAlpha(100);
    } else {

The mSelectedItemsIds is not altered during my testing. I am inserting entries to the list. After exactly 12 entries it crashes on mSelectedItemsIds.valueAt(position) with ArrayIndexOutOfBound at 11. On another device it crashes after 14 inserts. The size of the array is always 0 before every check.

How is that possible?

Here are all relevant parts of the adapter class (I cut out On Click listener, that are never triggered)

public class TaskArrayAdapter extends ArrayAdapter<Task> {
// Array with all selectedIds
private SparseBooleanArray mSelectedItemsIds;

public TaskArrayAdapter(@NonNull Context context, @NonNull List<Task> objects) {
    super(context, R.layout.item_task, objects);
    mSelectedItemsIds = new SparseBooleanArray();
    Log.d("Booleansize", String.valueOf(mSelectedItemsIds.size()));
}/**
 * Called for the ListView to get the view at position
 * @param position
 * @param convertView
 * @param parent
 * @return
 */
@NonNull
@Override
public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    // Get the data item for this position
    final Task task = getItem(position);
    // Check if an existing view is being reused, otherwise inflate the view
    if (convertView == null) {
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_task, parent, false);
    }
    // Lookup view for data population
    TextView tvDescription = (TextView) convertView.findViewById(R.id.tvDescription);
    TextView tvDueDate = (TextView) convertView.findViewById(R.id.tvDueDate);
    CheckBox cbDone = (CheckBox) convertView.findViewById(R.id.cbDone);
    // Populate the data into the template view using the data object
    tvDescription.setText(task.description);
    if (task.dueDate != null) {
        tvDueDate.setText(task.dueDate.toString());
    } else {
        tvDueDate.setText(R.string.no_due_date);
    }
    cbDone.setChecked(task.done);
    cbDone.setTag(position);
    convertView.setTag(position);

    // Set listeners
    cbDone.setOnClickListener(checkBoxListener);

    convertView.setOnClickListener(viewClickListener);

    convertView.setOnLongClickListener(viewLongClickListener);
    Log.d("Booleansize", String.valueOf(mSelectedItemsIds.size()));
    // check if the current item is selected for background color
    if (mSelectedItemsIds.valueAt(position)) {
        convertView.setBackgroundColor(Color.BLUE);
        convertView.getBackground().setAlpha(100);
    } else {
        convertView.setBackgroundColor(Color.TRANSPARENT);
        convertView.getBackground().setAlpha(255);
    }

    // Return the completed view to render on screen
    return convertView;
}/**
 * Change the isSelected value
 * @param position
 */
public void toggleSelection(int position) {
    selectView(position, !mSelectedItemsIds.get(position));
}

/**
 * Completely forget the current selection
 */
public void removeSelection() {
    mSelectedItemsIds = new SparseBooleanArray();
    notifyDataSetChanged();
}

/**
 * Set the select view to the given value
 * @param position
 * @param value
 */
public void selectView(int position, boolean value) {
    if (value) {
        mSelectedItemsIds.put(position, value);
    } else {
        mSelectedItemsIds.delete(position);
    }
    notifyDataSetChanged();
}

/**
 * get number of selected entries
 * @return
 */
public int getSelectedCount() {
    return mSelectedItemsIds.size();
}

public SparseBooleanArray getSelectedIds() {
    return mSelectedItemsIds;
}
Felix
  • 95
  • 2
  • 11

1 Answers1

0

You probably meant to use SparseBooleanArray.get method:

boolean get (int key)

Gets the boolean mapped from the specified key, or false if no such mapping has been made.

Use like so:

if (mSelectedItemsIds.get(position)) {
    convertView.setBackgroundColor(Color.BLUE);
    convertView.getBackground().setAlpha(100);
} else {
    ....
}

valueAt(int position) on the other hand takes position within the array, that's from 0 to size() - 1. You can use that to iterate over all values within the array.

Eugen Pechanec
  • 37,669
  • 7
  • 103
  • 124
  • That makes sense! But how is it possible, that the first 11 inserts work? Is it possible that the internal array is initialized with size 10? – Felix Jan 02 '18 at 18:49
  • Yes that is definitly the solution. And it does solve my second problem, which is the wrong entries to be colored... Thank you really much – Felix Jan 02 '18 at 18:57
  • `Is it possible that the internal array is initialized with size 10?` According to source default capacity really is 10 items. – Eugen Pechanec Jan 02 '18 at 20:09