Deleting items from a ListView using a custom BaseAdapter

12,749

You have to set the position each time. Your implementation only sets the position on the creation of the view. However when the view is recycled (when convertView is not null), the position will not be set to the correct value.

    public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.language_link_row, null);
        holder = new ViewHolder();
        holder.lang = (TextView)convertView.findViewById(R.id.language_link_text);

        final ImageView deleteButton = (ImageView) 
                convertView.findViewById(R.id.language_link_cross_delete);
        deleteButton.setOnClickListener(this);

        convertView.setTag(holder);
        deleteButton.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.lang.setText(mLanguages.get(position));
    holder.position = position;
    return convertView;
}
Share:
12,749
HXCaine
Author by

HXCaine

Hi

Updated on June 05, 2022

Comments

  • HXCaine
    HXCaine almost 2 years

    I am using a customised BaseAdapter to display items on a ListView. The items are just strings held in an ArrayList.

    The list items have a delete button on them (big red X), and I'd like to remove the item from the ArrayList, and notify the ListView to update itself.

    However, every implementation I've tried gets mysterious position numbers given to it, so for example clicking item 2's delete button will delete item 5's. It seems to be almost entirely random.

    One thing to note is that elements may be repeated, but must be kept in the same order. For example, I can have "Irish" twice, as elements 3 and 7.

    My code is below:

    private static class ViewHolder {
            TextView lang;
            int position;
    }
    
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.language_link_row, null);
            holder = new ViewHolder();
            holder.lang = (TextView)convertView.findViewById(R.id.language_link_text);
            holder.position = position;
    
            final ImageView deleteButton = (ImageView) 
                    convertView.findViewById(R.id.language_link_cross_delete);
            deleteButton.setOnClickListener(this);
    
            convertView.setTag(holder);
            deleteButton.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
    
        holder.lang.setText(mLanguages.get(position));
    
        return convertView;
    }
    

    I later attempt to retrieve the deleted element's position by grabbing the tag, but it's always the wrong position in the list. There is no noticeable pattern to the position given here, it always seems random.

    // The delete button's listener
    public void onClick(View v) {
    
        ViewHolder deleteHolder = (ViewHolder) v.getTag();
        int pos = deleteHolder.position;
    
        ...
        ...
        ...
    }
    

    I would be quite happy to just delete the item from the ArrayList and have the ListView update itself, but the position I'm getting is incorrect so I can't do that.

    Please note that I did, at first, have the deleteButton clickListener inside the getView method, and used 'position' to delete the value, but I had the same problem.

    Any suggestions appreciated, this is really irritating me.

  • Greg Giacovelli
    Greg Giacovelli over 13 years
    he has a button, so that listener will not be appropriate. That listener only works if the entire list element receives the click event.
  • HXCaine
    HXCaine over 13 years
    Brilliant, thank you. Can't believe I spent so long on such a silly problem. I've added my general solution as a separate answer for those interested.