问题
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?
回答1:
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:
- You weren't using the
ViewHolderpattern correctly. You never attached theViewHolderto theViewitself by usingsetTag()and you never retrieved theViewHolderfrom theViewwhen given a recycled view inconvertView. - If
convertViewwas 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 theViewfrom position 6 and ask for aViewfor position 1. In this case you would have just returned theViewfor position 6 (which isn't correct). - I've passed the actual
Taskobject into theonCheckChanged()method instead of passing the position and I've usedindexOf()to get the current position in the array for that object.
I hope this is helpful.
来源:https://stackoverflow.com/questions/11251065/how-to-remove-arraylist-item-and-then-update-listview