Updating child in ExpandableListView

I have an ExpandableListView style shopping cart.

enter image description here

I am trying to update a drawing suitable for drawing a child. All children start with "+" and I want this to change to "-" when clicked.

I tried to do this in the adapter, but when I scrolled through the list and opened the tabs of other groups, I noticed that the elements in those previously unclicked elements were also changed.

I'm not sure if I have an issue with the view refactoring in my adapter or if something else might be causing this. Here's my code:

GetChildView custom adapter method

    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View childView, ViewGroup parent) {

    final View row;
    final FullMenuItemHolder fullMenuItemHolder;

    if (childView == null) {

        LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.full_menu_child_item, parent, false);
        fullMenuItemHolder = new FullMenuItemHolder(row);
        row.setTag(fullMenuItemHolder);
    }

    else {
        row = childView;
        fullMenuItemHolder = (FullMenuItemHolder) row.getTag();
    }


    // set item name
    fullMenuItemHolder.title.setText(getChild(groupPosition, childPosition).getVenue_item_name());

    row.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            //check to see if item flagged as added to cart and set the respective drawable image
            if (!getChild(groupPosition,childPosition).getAddedToCart()) {
                getChild(groupPosition,childPosition).setAddedToCart(true);
                fullMenuItemHolder.title.setCompoundDrawablesWithIntrinsicBounds(null, null, fragment.getResources().getDrawable(R.drawable.remove), null);


            } else {
                getChild(groupPosition,childPosition).setAddedToCart(false);
                fullMenuItemHolder.title.setCompoundDrawablesWithIntrinsicBounds(null, null, fragment.getResources().getDrawable(R.drawable.add), null);

            }
        }
    });



    return row;
}

      

Adapter installed in fragment (called from onPostExecute in asyncTask after server load)

 fullMenuExpListAdapter = new FullMenuExpListAdapter(this.getActivity(), listHeaderNames, listChildItems, this);
 expandableListView.setAdapter(fullMenuExpListAdapter);

      

+3


source to share


1 answer


The row views are used again by the ListView, so clicks change multiple rows. If you tweak the list a little more, you'll also notice that the plus / minus signs are actually random, no matter which one you clicked on earlier.

After this line, you must manually update the composite drawings, similar to your OnClickListener:

// set item name
fullMenuItemHolder.title.setText(getChild(groupPosition, childPosition).getVenue_item_name());

      

This ensures that both new and reused strings display the correct icon.


(My response to your comment was too long.)

Actually there was nothing accidental for this problem, it was just a short explanation for me. :)



Think of it this way: Any line that completely leaves the screen is thrown into recycling when the last pixel is scrolled. It is left as is - no sub-clauses will be automatically cleared or changed.

When a new line enters the screen, the ListView first checks for a bunch of leftovers (the type of view required). If found, your adapter is given the only chance to update everything with the new data. If you forget to update anything, you will be left with leftovers from an earlier item - for example, the one selected in the original question.

But keep in mind that this applies not only to the visual state, but also to the behavior!

Unless you instantiated a new one OnClickListener

(for example, you placed the code in the if

above), groupPosition

and childPosition

would never change from the initial values, so pressing a row could update a completely different model object! While the user interface would appear to work correctly, the model would be inconsistent.

It might be helpful to move the view refresh logic from the adapter to your ViewHolder and give it a single method bindModel(ChildType child)

that sets the title, listeners, etc. It is easier to read and check that everything is installed correctly every time.
(The new RecyclerView works similarly; you should look at it.)


tl; dr: You have to make sure in your Adapter implementation to update whatever depends on the string data model, or the dragons will consume us all.

+2


source







All Articles