Noman Arain
Noman Arain

Reputation: 1162

How to remove arraylist item and then update listview

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

Answers (1)

David Wasser
David Wasser

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:

  1. You weren't using the 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.
  2. If 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).
  3. I've passed the actual 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

Related Questions