Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExpandableListAdapter onClickListener, call notifyDataSetChanged()

I have a custom adapter that uses an onclickListener to change the parent text, I can't figure out how to get the notifyDataSetChanged method to work within the adapter.

what should happen is I have an expandable view, and when you click on the button that is within the child it updates the parent with the text of the child...

Here's a picture example of what SHOULD happen. before clicking button USE THIS: enter image description here

and After clicking button USE THIS: enter image description here

"Choose an Ingredient" changes to "Rice, cups" or whatever is clicked on

so in my code shown, after clicking the button it should update parent, which it does, then refresh the view which I can't do for some reason?

heres my code, Thanks in advance!

    package com.example.andrew.mypantry;

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

import org.w3c.dom.Text;

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

/**
 * Created by andrew on 7/1/2015.
 */
public class IngExpandableListAdapter extends BaseExpandableListAdapter {

private Context context;
private List<String> listDataHeader; //header titles
//child data in format of <header title, child title>
private HashMap<String, List<String>> listDataChild;

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

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

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

private void test() {


    //notifyDataSetChanged();
    //super.notifyDataSetChanged();
    //this.notifyDataSetChanged();
}
@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 layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = layoutInflater.inflate(R.layout.ingredient_list_item, null);
    }

    TextView txtListChild = (TextView) convertView.findViewById(R.id.ingredientContentTextView);

    txtListChild.setText(childText);

    //handle button
    Button ingredientButton = (Button)convertView.findViewById(R.id.useIngredient_button);
    ingredientButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //change header to ingredient selected
            listDataHeader.set(groupPosition, childText);
            //test();
        }
    });

    return convertView;
}

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

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

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

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

@Override
public View getGroupView(int groupPosition, boolean isExpanded,
                         View convertView, ViewGroup parent) {

    String headerTitle = (String) getGroup(groupPosition);

    if(convertView == null) {
        LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
        convertView = layoutInflater.inflate(R.layout.ingredient_list_group, null);
    }

    //handle textView
    final TextView listHeader = (TextView) convertView.findViewById(R.id.ingredientGroupTextView);
    listHeader.setTypeface(null, Typeface.BOLD);
    listHeader.setText(headerTitle);

    //handle button
    Button deleteButton = (Button)convertView.findViewById(R.id.deleteButton);
    deleteButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //remove item from list
            Log.d("TESTING", "item should be removed");

        }
    });


    return convertView;
}

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

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

}

like image 785
Andrew Barta Avatar asked Jul 03 '15 18:07

Andrew Barta


2 Answers

As beworker mentioned, your problem comes from using wrong data structure and here is why your app crashes. You are using header titles as keys to your hashmap and when you modify a title in listDataHeader the modification is correctly applies to it but not to the key object inside the hashmap. Meaning that your children still exist under the old title key inside the hashmap and the new title key has null as its value. Thus you will get a NullPointerException when you call the

this.listDataChild.get(this.listDataHeader.get(groupPosition)).get(childPosition);

since

this.listDataChild.get(this.listDataHeader.get(groupPosition))

returns Null

Solution would be using ArrayList for header titles and ArrayList> for children. The key in both of these arrayLists is your group index.

like image 156
Kayvan N Avatar answered Nov 16 '22 11:11

Kayvan N


I believe the issue is in the data structures you use. You keep list of children assigned to the parent's name in a hash table. When parent's name changes in the list of parents, old children assignment in the hash table is not valid anymore.

I would suggest you to use SparseArray<List<String>> or List<List<String>> for listDataChild field. It will map group position to the list of children directly. Thus changing parent's name in listDataHeader wont break data consistency, as the group position will stay the same. Now you should be able to safely use notifyDataSetChanged() method to update headers.

Hope this helps.

like image 28
sergej shafarenka Avatar answered Nov 16 '22 09:11

sergej shafarenka