Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
208 views
in Technique[技术] by (71.8m points)

java - Values of counter changes after scrolling ExpendableListView

I have an ExpandableListView of items and on list item I have TextView with two buttons to increment or decrements the value in TextView on clicks. The problem occurs every time I try to scroll the list. If I increment one item and then scroll the list the values get mixed (becouse the ListView keeps recycling its views) and I don't know how to fix it.

I have tried many soulutions I have found here, so yes this may be a duplicate, but I wasn't able to solve my problem with any method I have found.

My ExpandableListAdapter.java

    import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.TextView;

import java.util.HashMap;
import java.util.List;


public class ExpandableListAdapter extends BaseExpandableListAdapter {

public static class ViewHolder {
    TextView childText;
    TextView counterText;
    Button addItemButton;
    Button deleteItemButton;

    int quantity = 0;

}


private Context context;
private List<String> listDataHeader;
private HashMap<String, List<String>> listHashMap;

public ExpandableListAdapter(Context context, List<String> listDataHeader, HashMap<String, List<String>> listHashMap) {
    this.context = context;
    this.listDataHeader = listDataHeader;
    this.listHashMap = listHashMap;
}

@Override
public int getGroupCount() {
    return listDataHeader.size();
}

@Override
public int getChildrenCount(int groupPosition) {
    return listHashMap.get(listDataHeader.get(groupPosition)).size();
}

@Override
public Object getGroup(int groupPosition) {
    return listDataHeader.get(groupPosition);
}

@Override
public Object getChild(int groupPosition, int childPosition) {
    return listHashMap.get(listDataHeader.get(groupPosition)).get(childPosition);
}

@Override
public long getGroupId(int groupPosition) {
    return groupPosition;
}

@Override
public long getChildId(int groupPosition, int childPosition) {
    return childPosition;
}

@Override
public boolean hasStableIds() {
    return false;
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    String headerTitle = (String) getGroup(groupPosition);

    if(convertView == null) {
        LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_group, null);

    }
    TextView listHeader = (TextView) convertView.findViewById(R.id.list_header);
    listHeader.setTypeface(null, Typeface.BOLD);
    listHeader.setText(headerTitle);

    return convertView;
}

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

    final ViewHolder viewHolder;

    if(convertView == null) {
        LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_item, null);

        TextView textListChild = (TextView) convertView.findViewById(R.id.list_item_header);
        TextView itemsCounter = (TextView) convertView.findViewById(R.id.items_counter);
        Button addItemButton = (Button) convertView.findViewById(R.id.plus_btn);

        viewHolder = new ViewHolder();
        viewHolder.childText = textListChild;
        viewHolder.counterText = itemsCounter;
        viewHolder.addItemButton = addItemButton;

        convertView.setTag(viewHolder);


    } else {
        viewHolder = (ViewHolder) convertView.getTag();

    }

    final String childText = (String) getChild(groupPosition, childPosition);
    viewHolder.childText.setText(childText);

    viewHolder.addItemButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            //int itemCount = Integer.parseInt((String)viewHolder.counterText.getText());
            //itemCount++;

            viewHolder.quantity++;
            viewHolder.counterText.setText( Integer.toString(viewHolder.quantity));

            PutOrderDrinks.addOrder(childText);

        }
    });


    return convertView;
}

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
       return true;
    } 
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It is not a good idea to store quantity in ViewHolder. Hope below sample helps :)

MainActivity.java:

public class MainActivity extends Activity {

Button clearChecks, putOrder;
ExpandableListView expandableListView;
ExpandableListViewAdapter expandableListAdapter;
int lastExpandedPosition = -1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    expandableListView = findViewById(R.id.expandedListView);
    clearChecks = findViewById(R.id.btnClearChecks);
    putOrder = findViewById(R.id.btnPutOrder);

    List<String> listTitle = genGroupList();
    expandableListAdapter = new ExpandableListViewAdapter(this, listTitle, genChildList(listTitle));
    expandableListView.setAdapter(expandableListAdapter);

    expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
        @Override
        public void onGroupExpand(int groupPosition) {
            if(lastExpandedPosition != -1 && (lastExpandedPosition != groupPosition)){
                expandableListView.collapseGroup(lastExpandedPosition);
            }
            lastExpandedPosition = groupPosition;
        }
    });
    clearChecks.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            expandableListAdapter.clearChecks();
        }
    });
    putOrder.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            ArrayList<ChildItemSample> putOrder = expandableListAdapter.getOrderList();
            String msg = "";
            for(int i=0; i<putOrder.size(); i++){
                msg += putOrder.get(i).getName() + ": " + putOrder.get(i).getQty() + "
";
            }
            Toast.makeText(getBaseContext(), msg, Toast.LENGTH_LONG).show();
        }
    });
}

private ArrayList<String> genGroupList(){
    ArrayList<String> listGroup = new ArrayList<>();
    for(int i=1; i<10; i++){
        listGroup.add("Group: " + i);
    }
    return listGroup;
}

private Map<String, List<ChildItemSample>> genChildList(List<String> header){
    Map<String, List<ChildItemSample>> listChild = new HashMap<>();
    for(int i=0; i<header.size(); i++){
        List<ChildItemSample> testDataList = new ArrayList<>();
        int a = (int)(Math.random()*8);
        for(int j=0; j<a; j++){
            ChildItemSample testItem = new ChildItemSample("Child " + (j + 1), 0);
            testDataList.add(testItem);
        }
        listChild.put(header.get(i), testDataList);
    }
    return listChild;
}
}

ChildItemSample.java:

public class ChildItemSample {
private boolean checked = false;
private String name;
private int qty;

public int getQty() {
    return qty;
}

public void setQty(int qty) {
    this.qty = qty;
}

public boolean isChecked() {
    return checked;
}

public void setChecked(boolean checked) {
    this.checked = checked;
}

public String getName() {
    return name;
}

public ChildItemSample(String name, int qty){
    this.name = name;
    this.qty = qty;
}
}

ExpandableListViewAdapter.java:

public class ExpandableListViewAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> listGroup;
private Map<String, List<ChildItemSample>> listChild;
private int checkedBoxesCount;
private boolean[] checkedGroup;

public ExpandableListViewAdapter(Context context, List<String> listGroup, Map<String,
        List<ChildItemSample>> listChild) {
    this.context = context;
    this.listGroup = listGroup;
    this.listChild = listChild;
    checkedBoxesCount = 0;
    checkedGroup = new boolean[listGroup.size()];
}

@Override
public int getGroupCount() {
    return listGroup.size();
}

@Override
public int getChildrenCount(int groupPosition) {
    return listChild.get(listGroup.get(groupPosition)).size();
}

@Override
public String getGroup(int groupPosition) {
    return listGroup.get(groupPosition);
}

@Override
public ChildItemSample getChild(int groupPosition, int childPosition) {
    return listChild.get(listGroup.get(groupPosition)).get(childPosition);
}

@Override
public long getGroupId(int groupPosition) {
    return groupPosition;
}

@Override
public long getChildId(int groupPosition, int childPosition) {
    return childPosition;
}

@Override
public boolean hasStableIds() {
    return false;
}

@Override
public View getGroupView(int groupPosition, boolean b, View view, ViewGroup viewGroup) {
    String itemGroup = getGroup(groupPosition);
    GroupViewHolder groupViewHolder;
    if(view == null){
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.expanded_list_group, null);
        groupViewHolder = new GroupViewHolder();
        groupViewHolder.tvGroup = view.findViewById(R.id.tv_group);
        groupViewHolder.cbGroup = view.findViewById(R.id.cb_group);
        groupViewHolder.cbGroup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int pos = (int)view.getTag();
                checkedGroup[pos] = !checkedGroup[pos];
                for(ChildItemSample item : listChild.get(listGroup.get(pos))){
                    item.setChecked(checkedGroup[pos]);
                }
                notifyDataSetChanged();
            }
        });
        view.setTag(groupViewHolder);
    }else {
        groupViewHolder = (GroupViewHolder)view.getTag();
    }
    groupViewHolder.tvGroup.setText(String.format("%s (%d)", itemGroup, getChildrenCount(groupPosition)));
    if(checkedGroup[groupPosition]) groupViewHolder.cbGroup.setChecked(true);
    else groupViewHolder.cbGroup.setChecked(false);
    groupViewHolder.cbGroup.setTag(groupPosition);
    return view;
}

@Override
public View getChildView(int groupPosition, int childPosition, boolean b, View view, ViewGroup viewGroup) {
    ChildItemSample expandedListText = getChild(groupPosition,childPosition);
    ChildViewHolder childViewHolder;
    if(view == null){
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.expanded_list_item, null);
        childViewHolder = new ChildViewHolder();
        childViewHolder.tvChild = view.findViewById(R.id.tv_child);
        childViewHolder.cbChild = view.findViewById(R.id.cb_child);
        childViewHolder.tvQty = view.findViewById(R.id.tv_qty);
        childViewHolder.btInc = view.findViewById(R.id.bt_inc);
        childViewHolder.btDec = view.findViewById(R.id.bt_dec);
        childViewHolder.cbChild.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                CheckBox cb = (CheckBox) view;
                Pos pos = (Pos) cb.getTag();
                ChildItemSample selectedItem = getChild(pos.group, pos.child);
                selectedItem.setChecked(cb.isChecked());
                if(cb.isChecked()){
                    checkedBoxesCount++;
                    Toast.makeText(context,"Checked value is: " + getChild(pos.group, pos.child).getName(),
                            Toast.LENGTH_SHORT).show();
                }else {
                    checkedBoxesCount--;
                    if(checkedBoxesCount == 0){
                        Toast.makeText(context,"nothing checked",Toast.LENGTH_SHORT).show();
                    }else {
                        Toast.makeText(context,"unchecked",Toast.LENGTH_SHORT).show();
                    }
                }
                notifyDataSetChanged();
            }
        });
        childViewHolder.btInc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Button bt = (Button) view;
                Pos pos = (Pos) bt.getTag();
                ChildItemSample selectedItem = getChild(pos.group, pos.child);
                selectedItem.setQty(selectedItem.getQty() + 1);
                notifyDataSetChanged();
            }
        });
        childViewHolder.btDec.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Button bt = (Button) view;
                Pos pos = (Pos) bt.getTag();
                ChildItemSample selectedItem = getChild(pos.group, pos.child);
                if(selectedItem.getQty() > 0) selectedItem.setQty(selectedItem.getQty() - 1);
                notifyDataSetChanged();
            }
        });
    }else {
        childViewHolder = (ChildViewHolder)view.getTag();
    }
    childViewHolder.cbChild.setChecked(expandedListText.isChecked());
    childViewHolder.tvChild.setText(expandedListText.getName() + " :");
    childViewHolder.tvQty.setText("" + expandedListText.getQty());

    childViewHolder.cbChild.setTag(new Pos(groupPosition, childPosition));
    childViewHolder.btInc.setTag(new Pos(groupPosition, childPosition));
    childViewHolder.btDec.setTag(new Pos(groupPosition, childPosition));
    view.setTag(childViewHolder);
    return view;
}

public void clearChecks() {
    for(int i=0; i<checkedGroup.length; i++) checkedGroup[i] = false;
    for(List<ChildItemSample> value : listChild.values()) {
        for (ChildItemSample sample : value) {
            sample.setChecked(false);
        }
    }
    checkedBoxesCount = 0;
    notifyDataSetChanged();
}

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
    return true;
}

private class GroupViewHolder {
    CheckBox cbGroup;
    TextView tvGroup;
}

private class ChildViewHolder {
    CheckBox cbChild;
    TextView tvChild;
    TextView tvQty;
    Button btInc;
    Button btDec;
}

private class Pos {
    int group;
    int child;

    Pos(int group, int child){
        this.group = group;
        this.child = child;
    }
}

public ArrayList<ChildItemSample> getOrderList(){
    ArrayList<ChildItemSample> overallOrder = new ArrayList<>();
    for(int i=0; i<getGroupCount(); i++){
        for(int j=0; j<getChildrenCount(i); j++){
            if(getChild(i,j).getQty() > 0){
                ChildItemSample newOrder = new ChildItemSample(getGroup(i) + ">" +
                        getChild(i, j).getName(), getChild(i, j).getQty());
                overallOrder.add(newOrder);
            }
        }
    }
    return overallOrder;
}
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
            <Button
                android:id="@+id/btnClearChecks"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Clear Checks" />
            <Button
                android:id="@+id/btnPutOrder"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...