Reputation: 1162
ListView listView;
Activity activity;
public ArrayList<Tasks> tasks;
View v;
public TaskAdapter(Activity activity, ArrayList<Tasks> tasks)
{
super(activity, R.layout.presenterlayout, tasks);
this.activity = activity;
this.tasks = tasks;
}
static class ViewHolder {
public TextView taskTitleTextView;
public TextView taskDescriptionTextView;
public TextView taskDueTimeTextView;
public CheckBox checkBox;
}
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
v = convertView;
if (v == null) {
LayoutInflater inflator = activity.getLayoutInflater();
v = inflator.inflate(R.layout.presenterlayout, null, false);
listView = (ListView) v.findViewById(R.id.listView);
holder = new ViewHolder();
holder.taskTitleTextView = (TextView) v.findViewById(R.id.taskTitleTextView);
holder.taskDescriptionTextView = (TextView) v.findViewById(R.id.taskDescriptionTextView);
holder.taskDueTimeTextView = (TextView) v.findViewById(R.id.taskDueTimeTextView);
holder.checkBox = (CheckBox) v.findViewById(R.id.checkBox);
holder.taskTitleTextView.setText(tasks.get(position).getTasksTitleString());
holder.taskDescriptionTextView.setText(tasks.get(position).getTasksDescriptionString());
holder.taskDueTimeTextView.setText(tasks.get(position).getTasksDueTimeString());
holder.checkBox.setId(position);
holder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(holder.checkBox.isChecked())
{
System.out.println("postion: " + position);
if(tasks.get(position).isTasksCompleted().equals("true"))
{
tasks.get(position).setTasksCompleted("false");
}
else if(tasks.get(position).isTasksCompleted().equals("false"))
{
tasks.get(position).setTasksCompleted("true");
}
updateThisTask(tasks.get(position));
tasks.remove(position);
notifyDataSetChanged();
}
}
});
}
else {
v = convertView;
}
return v;
}
private void updateThisTask(Tasks tasks) {
DBAdapter dbAdapter = new DBAdapter(getContext());
int id = dbAdapter.getID(tasks);
dbAdapter.updateTask(tasks, id);
}
}
I want to remove item from the array list. As you can see I am using checkbox. The first time I click the checkbox, correct item is removed. The second time if I click the checkbox, the application crashes due to index out of bounds. How can I remove an item from the array list called tasks and update the listview?
Upvotes: 0
Views: 3495
Reputation: 95578
Once you remove an item from the tasks
array, all of the items after that get a new index so all of the position
values that you've saved in the holders and passed to the OnCheckedChangeListener
are wrong. I fyou want to do this this way, you can't rely on using the position in the array as a way of finding an entry. You'll need to use the object itself and search the array to find the matching object. Use something like
int arrayIndexOfThisTask = tasks.indexOf(objectThatIsInTheArray);
EDIT: Add code example:
Try this:
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
v = convertView;
if (v == null) {
LayoutInflater inflator = activity.getLayoutInflater();
v = inflator.inflate(R.layout.presenterlayout, null, false);
listView = (ListView) v.findViewById(R.id.listView);
holder = new ViewHolder();
v.setTag(holder); // Attach the holder to the view so we can find it again
holder.taskTitleTextView = (TextView) v.findViewById(R.id.taskTitleTextView);
holder.taskDescriptionTextView = (TextView) v.findViewById(R.id.taskDescriptionTextView);
holder.taskDueTimeTextView = (TextView) v.findViewById(R.id.taskDueTimeTextView);
holder.checkBox = (CheckBox) v.findViewById(R.id.checkBox);
} else {
// Get the ViewHolder from the recycled view
holder = (ViewHolder)v.getTag();
}
// Get the task at this position in the array
final Task task = tasks.get(position);
holder.taskTitleTextView.setText(task.getTasksTitleString());
holder.taskDescriptionTextView.setText(task.getTasksDescriptionString());
holder.taskDueTimeTextView.setText(task.getTasksDueTimeString());
holder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(holder.checkBox.isChecked())
{
// Try to find the position in the array for this object (it may already have been removed)
int position = tasks.indexOf(task);
System.out.println("postion: " + position);
// If this object is no longer in the array, just ignore this action
if (position >= 0) {
if(tasks.get(position).isTasksCompleted().equals("true"))
{
tasks.get(position).setTasksCompleted("false");
}
else if(tasks.get(position).isTasksCompleted().equals("false"))
{
tasks.get(position).setTasksCompleted("true");
}
updateThisTask(tasks.get(position));
tasks.remove(position);
notifyDataSetChanged();
}
}
}
});
return v;
}
I may not have everything exactly right, but you should get the idea.
There were actually many things wrong with your code:
ViewHolder
pattern correctly. You never attached the ViewHolder
to the View
itself by using setTag()
and you never retrieved the ViewHolder
from the View
when given a recycled view in convertView
.convertView
was non-null you just returned it without doing anything with it. This is wrong because the adapter recycles views any way it wants to and it may pass you the View
from position 6 and ask for a View
for position 1. In this case you would have just returned the View
for position 6 (which isn't correct).Task
object into the onCheckChanged()
method instead of passing the position and I've used indexOf()
to get the current position in the array for that object.I hope this is helpful.
Upvotes: 4