Title: Android - ExpandableListView with Custom ExpandableListAdapter with Delete Button inside Child Rows
Tags: android;android-studio;expandablelistview;custom-adapter;expandablelistadapter
Question: I have try an ExpandableListView with custom Adapter, with an Add Button in every group row that can add a child row below it with only one click on the Add Button. in every child row, there are two plain text input with a delete button for deleting the row that the delete button placed. But after I create the code for deleting the row, i have problem with the deleted data.
Here is the display after i fill in the plain text input and before i click the second delete button (red circle).
Here is the display after i click the second delete button in the previous link. This picture shows that the deleted child row is not the second one, but the deleted one is the last one (i have checked the arraylist inside my custom adapter value, and the deleted value is correct). Even i click the other one except the last, the deleted row is always the last one.
Here is my codes for the Custom Adapter Class:
package com.orderpakan.japfa.androiddynamicwidget;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import java.util.ArrayList;
public class CustomExpandListAdapter extends BaseExpandableListAdapter {
private static Context mycontext;
private ArrayList<Truk&gt; trukList;
private OnItemSelectedListener onItemSelectedCallback;
public interface OnItemSelectedListener {
public void onButtonAddClick(int groupPosition);
public void onButtonDeleteClick(int groupPosition, int childPosition);
public CustomExpandListAdapter(Context c){
mycontext = c;
trukList = new ArrayList<Truk&gt;();
trukList.add(new Truk("Aaaaaa", "This is the remarks for Aaaaaa"));
trukList.add(new Truk("Bbbbbb", "This is the remarks for Bbbbbb"));
trukList.add(new Truk("Cccccc", "This is the remarks for Cccccc"));
trukList.add(new Truk("Dddddd", "This is the remarks for Dddddd"));
trukList.add(new Truk("Eeeeee", "This is the remarks for Eeeeee"));
try {
this.onItemSelectedCallback = (OnItemSelectedListener) mycontext;
}
catch (ClassCastException e) {
throw new ClassCastException(mycontext.toString() + " must implement OnItemSelectedListener ");
}
@Override
public int getGroupCount() {
return trukList.size();
@Override
public int getChildrenCount(int groupPosition) {
return trukList.get(groupPosition).getPakanList().size();
@Override
public Truk getGroup(int groupPosition) {
return trukList.get(groupPosition);
@Override
public Pakan getChild(int groupPosition, int childPosition) {
return trukList.get(groupPosition).getPakanList().get(childPosition);
@Override
public long getGroupId(int groupPosition) {
return 0;
@Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
@Override
public boolean hasStableIds() {
return false;
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null) {
LayoutInflater inflater = (LayoutInflater) mycontext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflater.inflate(R.layout.list_header, parent, false);
}
TextView txtNamaTruk = (TextView) vi.findViewById(R.id.txtNamaTruk);
TextView txtDetailTruk = (TextView) vi.findViewById(R.id.txtDetailTruk);
ImageButton imageAdd = (ImageButton) vi.findViewById(R.id.imageAdd);
Truk tempTruk = trukList.get(groupPosition);
txtNamaTruk.setText(tempTruk.getNama());
txtDetailTruk.setText(tempTruk.getDesc());
imageAdd.setImageResource(android.R.drawable.ic_input_add);
imageAdd.setScaleType(ImageButton.ScaleType.FIT_CENTER);
imageAdd.setFocusable(false);
imageAdd.setClickable(true);
imageAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
trukList.get(groupPosition).getPakanList().add(new Pakan());
CustomExpandListAdapter.this.notifyDataSetChanged();
onItemSelectedCallback.onButtonAddClick(groupPosition);
}
});
return vi;
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null) {
LayoutInflater inflater = (LayoutInflater) mycontext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflater.inflate(R.layout.list_detail, parent, false);
}
EditText editPakan = (EditText) vi.findViewById(R.id.editPakan);
editPakan.setClickable(true);
EditText editSak = (EditText) vi.findViewById(R.id.editSak);
editSak.setClickable(true);
ImageButton imageDelete = (ImageButton) vi.findViewById(R.id.imageDelete);
imageDelete.setImageResource(android.R.drawable.ic_input_delete);
imageDelete.setScaleType(ImageButton.ScaleType.FIT_CENTER);
imageDelete.setFocusable(false);
imageDelete.setClickable(true);
trukList.get(groupPosition).getPakanList().get(childPosition).setTxtNama(editPakan);
trukList.get(groupPosition).getPakanList().get(childPosition).setTxtJmlhSak(editSak);
imageDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
trukList.get(groupPosition).getPakanList().remove(childPosition);
CustomExpandListAdapter.this.notifyDataSetChanged();
onItemSelectedCallback.onButtonDeleteClick(groupPosition, childPosition);
}
});
return vi;
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
And here is the Activity Code for calling the ExpandableListView:
package com.orderpakan.japfa.androiddynamicwidget;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ExpandableListView;
import android.widget.Toast;
public class ListDropDownActivity extends AppCompatActivity implements CustomExpandListAdapter.OnItemSelectedListener {
private ExpandableListView expand1;
private CustomExpandListAdapter adapter;
private Button btnView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_drop_down);
expand1 = (ExpandableListView) findViewById(R.id.expand1);
adapter = new CustomExpandListAdapter(this);
expand1.setAdapter(adapter);
btnView = (Button) findViewById(R.id.btnView);
btnView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String teks = "";
for (int i = 0; i < adapter.getGroupCount(); i++) {
Truk tempTruk = (Truk) adapter.getGroup(i);
teks += "Truk: " + tempTruk.getNama() + " (" + tempTruk.getDesc() + ")\n";
for (int j = 0; j < adapter.getChildrenCount(i); j++) {
teks += "- Pakan: " + adapter.getChild(i,j).getTxtNama().getText().toString() + " (" + adapter.getChild(i,j).getTxtJmlhSak().getText().toString() + " sak)\n";
}
teks += "\n";
}
Toast.makeText(ListDropDownActivity.this, teks, Toast.LENGTH_LONG).show();
}
});
@Override
public void onButtonAddClick(int groupPosition) {
expand1.expandGroup(groupPosition);
@Override
public void onButtonDeleteClick(int groupPosition, int childPosition) {
if(adapter.getChildrenCount(groupPosition)==0) {
expand1.collapseGroup(groupPosition);
}
Is there any mistake in my code? Or is there any missing section in my code?
Please help me to solve this problem.


Here is another answer: Here is what I do in my ExpandableListAdapter that does the trick:
public class ExpandableListAdapter extends BaseExpandableListAdapter {
private Context _context;
private List<String&gt; _listDataHeader;
private HashMap<String, List<String&gt;&gt; _listDataChild;
public ExpandableListAdapter(Context context, List<String&gt; listDataHeader,
HashMap<String, List<String&gt;&gt; listChildData) {
this._context = context;
this._listDataHeader = listDataHeader;
this._listDataChild = listChildData;
@Override
public View getChildView(final int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final String childText = (String) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.list_item, null);
TextView txtListChild = (TextView) convertView
.findViewById(R.id.lblListItem);
txtListChild.setText(childText);
Button delete = (Button) convertView.findViewById(R.id.remove_item_button);
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
_listDataChild.get(_listDataHeader.get(groupPosition)).remove(childPosition);
ExpandableListAdapter.this.notifyDataSetChanged();
}
});
return convertView;

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2016:00:02/04/16', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<android><android-studio><expandablelistview><custom-adapter><expandablelistadapter>', 'Title': 'Android - ExpandableListView with Custom ExpandableListAdapter with Delete Button inside Child Rows', 'ViewCount': 1273, 'id': 35196607, 'user_AboutMe': '<p>A System Analyst and Programmer at PT. Japfa Comfeed Indonesia. In charge in developing application with APEX and Android.</p>\n', 'user_AccountId': 3915880.0, 'user_DisplayName': 'Eddy Christian', 'user_Reputation': 11.0, 'user_Views': 3.0, 'user_id': 3239705.0}}