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