I am trying to use an ExpandableListView to display a list of items with their children. I would like each child to have 2 radio buttons (Yes and No). When the No button is clicked, an EditText should appear in which the user should enter some text.
When the user clicks the save button I would like to save the data.
After some research I think it is best to update the child objects as they change rather than try and retrieve it all at once on a button click. So my code attempts to show this in action. If this is not the best approach please let me know.
My issue is that UNEXPECTED children are updated when I edit one.
I've looked at the following links (amongst many!) but not had success.
https://www.digitalocean.com/community/tutorials/android-expandablelistview-example-tutorial how to fetch data from multiple edit text in child view of expandable list view? https://www.geeksforgeeks.org/baseexpandablelistadapter-in-android-with-example/
ExpandableListAdapter
public class MyExpandableListAdapter extends BaseExpandableListAdapter{
private Context context;
private List<Parent> parents;
private HashMap<Parent, List<Child>> children;
public MyExpandableListAdapter(Context context, List<Parent> parents, HashMap<Parent, List<Child>> children){
this.context = context;
this.parents = parents;
this.children = children;
}
@Override
public Child getChild(int listPosition, int expandedListPosition){
return this.children.get(this.parents.get(listPosition)).get(expandedListPosition);
}
@Override
public long getChildId(int listPosition, int expandedListPosition){
return this.getChild(listPosition, expandedListPosition).getId();
}
@Override
public View getChildView(final int listPosition, final int expandedListPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null)
{
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.child_layout, parent, false);
}
TextView text = (TextView) convertView.findViewById(R.id.child_text);
RadioButton yesButton = (RadioButton)convertView.findViewById(R.id.yes_button);
RadioButton noButton = (RadioButton)convertView.findViewById(R.id.no_button);
EditText negativeResponse = (EditText)convertView.findViewById(R.id.no_response);
Child child = getChild(listPosition, expandedListPosition);
child.setResponse(true);
if (child != null)
{
text.setText(child.getText());
}
negativeResponse.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus){
String response = negativeResponse.getText().toString();
child.setNegativeResponse(response);
child.setResponse(response == null || response.isEmpty());
}
}
});
yesButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
negativeResponse.setVisibility(View.GONE);
child.setResponse(true);
child.setNegativeResponse(null);
}
});
noButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
negativeResponse.setVisibility(View.VISIBLE);
child.setResponse(false);
}
});
return convertView;
}
@Override
public int getChildrenCount(int listPosition) {
return this.children.get(this.parents.get(listPosition)).size();
}
@Override
public Parent getGroup(int listPosition) {
return this.parents.get(listPosition);
}
@Override
public int getGroupCount() {
return this.parents.size();
}
@Override
public long getGroupId(int listPosition) {
return this.getGroup(listPosition).getOid();
}
@Override
public View getGroupView(int listPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
Parent parent = getGroup(listPosition);
if (convertView == null) {
LayoutInflater layoutInflater = (LayoutInflater) this.context.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.parent_layout, null);
}
TextView parentCode = (TextView) convertView.findViewById(R.id.code);
parentCode.setText(parent.getCode());
TextView parentDescription = (TextView) convertView.findViewById(R.id.description);
parentDescription.setText(parent.getDescription());
return convertView;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int listPosition, int expandedListPosition) {
return true;
}
}
Parent
public class Parent {
private int id;
private String code;
private String description;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Child
public class Child {
private int id;
private String text;
private boolean response;
private String negativeResponse;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getText() {
return questionText;
}
public void setText(String text) {
this.text = text;
}
public boolean isAffirmativeResponse() {
return response;
}
public void setResponse(boolean response) {
this.response = response;
}
public String getNegativeResponse() {
return negativeResponse;
}
public void setNegativeResponse(String negativeResponse) {
this.negativeResponse = negativeResponse;
}
Activity
public class MyActivity {
private MyExpandableListAdapter listAdapter;
private ExpandableListView dataView;
@Override
public void onResume() {
dataView = (ExpandableListView) findViewById(R.id.dataView);
this.listAdapter = new MyExpandableListAdapter(this.getContext(), this.getParents(), this.getChildren());
dataView.setAdapter(this.listAdapter);
}
private List<Parent> getParents() {
// Gets the list of parents
}
private List<Child> getChildren() {
// Gets the list of children
}
}
Parent-Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textStyle="bold" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textStyle="bold" />
</RelativeLayout>
Child-Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:paddingRight="5dp"
android:orientation="horizontal">
<TextView
android:id="@+id/child_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"/>
<RadioGroup
android:id="@+id/radio_group"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/child_text">
<RadioButton
android:id="@+id/no_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/no"/>
<RadioButton
android:id="@+id/yes_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dp"
android:checked="true"
android:text="@string/yes"/>
</RadioGroup>
</RelativeLayout>
<EditText
android:id="@+id/negative_response"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:visibility="gone"/>
</RelativeLayout>
Say I have the data in the format
If I edit Child 1a, Child 2c mirrors the changes I made.
If I edit Child 1b, Child 2c mirrors the changes I made.
If I edit Child 1c, Child 2d mirrors the changes I made.
If I edit Child 1d, Child 2e mirrors the changes I made.
I feel I've made a really elementary mistake but I can't see it. How can I edit the correct child and ONLY the correct child so I can save the data?
It was down to the way I was picking which Child to display and how they were displaying. The fixed getChildView
is below
@Override
public View getChildView(final int listPosition, final int expandedListPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.child_layout, parent, false);
}
TextView text = (TextView) convertView.findViewById(R.id.child_text);
final RadioButton yesButton = (RadioButton) convertView.findViewById(R.id.yes_button);
final RadioButton noButton = (RadioButton) convertView.findViewById(R.id.no_button);
final EditText negativeResponse = (EditText) convertView.findViewById(R.id.no_response);
final Child child = getChild(listPosition, expandedListPosition);
if (child != null) {
text.setText(child.getText());
}
negativeResponse.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
response.setNegativeResponse(negativeResponse.getText().toString());
}
}
});
yesButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
negativeResponse.setVisibility(View.GONE);
response.setPositiveQuestionResponse(true);
response.setNegativeResponse("");
}
});
noButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
negativeResponse.setVisibility(View.VISIBLE);
response.setPositiveQuestionResponse(false);
}
});
return convertView;
}