Israel Merljak
Israel Merljak

Reputation: 241

ExpandableListView repeating child nodes

I've implemented an ExpandableListAdapter, and it's working fine apparently. Except that when the activity resumes, the child nodes get repeated. I don't know how to fix this, I've searched online for this and found nothing helpful.

I've mitigated the problem adding some != null checks. Thus avoiding the insertion and creation of new data when not needed. But that hasn't fixed the problem.

Here's the CustomAdapter

public class ContatoAdapter extends BaseExpandableListAdapter {

private final Activity context;
private final Map<String, List<Contato>> contatosCollection;
private final List<String> area;

public ContatoAdapter(Activity context, List<String> area, Map<String, List<Contato>> contatosCollection) {
    this.context = context;
    this.contatosCollection = contatosCollection;
    this.area = area;
}

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

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


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

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

@Override
public long getGroupId(int groupPosition) {
    return this.area.get(groupPosition).hashCode();
}

@Override
public long getChildId(int groupPosition, int childPosition) {
    return this.contatosCollection.get(this.area.get(groupPosition)).get(childPosition).hashCode();
}

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

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    String s = (String) getGroup(groupPosition);
    final LayoutInflater gInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (convertView == null){
        convertView = gInflater.inflate(R.layout.group_item, parent, false);
    }

    final TextView item = (TextView) convertView.findViewById(R.id.list_header);

    item.setText(s);
    item.setTypeface(null, Typeface.BOLD);

    return convertView;
}

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
    final Contato contato = (Contato) getChild(groupPosition, childPosition);
    final LayoutInflater cInflater = this.context.getLayoutInflater();

    if (convertView == null){
        convertView = cInflater.inflate(R.layout.list_item, parent, false);
    }

    TextView item = (TextView) convertView.findViewById(R.id.list_item_nome);
    ImageView ver = (ImageView) convertView.findViewById(R.id.list_item_ver);

    ver.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(context.getApplicationContext(), DetalheActivity.class);
            intent.putExtra("contato", contato);
            context.startActivity(intent);
        }
    });

    item.setText(contato.getNome());

    return convertView;
}

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

Here's the activity that has the listView with the adapter:

public class MedicosActivity extends AppCompatActivity {
private ExpandableListView listView;
private ArrayList<Contato> contatos;
private ArrayList<String> areas;
private HashMap<String, List<Contato>> contatosCollection;
private ContatoAdapter adapter;

String jsonString = "";

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

    setTitle("Médicos | Etc");

    init();

    if (listView == null)
        listView = (ExpandableListView) findViewById(android.R.id.list);
    adapter = new ContatoAdapter(this,areas,contatosCollection);
    listView.setAdapter(adapter);

    listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
        @Override
        public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
            Contato selected = (Contato) adapter.getChild(groupPosition,childPosition);
            Toast.makeText(MedicosActivity.this, selected.getNome() , Toast.LENGTH_SHORT).show();

            return true;
        }
    });
}

private void init() {
    if (jsonString.isEmpty())
        jsonString =  JsonUtil.loadJSON(MedicosActivity.this, "data.json");
    if (contatosCollection == null)
        contatos = JsonUtil.parseJSON(jsonString);
    if (areas == null){
        areas = new ArrayList<>();
        createGroupList();
    }
    if (contatosCollection == null){
        contatosCollection = new HashMap<>();
        createCollection();
    }
}

private void createGroupList() {
    for(Contato c : contatos){
        if (!areas.contains(c.getArea())){
            areas.add(c.getArea());
        }
    }
}

private void createCollection() {
    for (Contato c : contatos){
        List<Contato> ctg = contatosCollection.get(c.getArea());
        if (ctg == null){
            ctg = new ArrayList<>();
            contatosCollection.put(c.getArea(), ctg);
        }
        ctg.add(c);
    }
}
}

Adding the JSON Parser class that caused the error:

private static ArrayList<Contato> contatoList = new ArrayList<>();
public static ArrayList<Contato> parseJSON(String jsonString){
    try {
        JSONObject jsonObject = new JSONObject(jsonString);
        JSONArray jsonArray = jsonObject.optJSONArray("medicos");

        for (int i = 0; i < jsonArray.length(); i++){
            JSONObject medicoObj = jsonArray.getJSONObject(i);
             JSONObject end = medicoObj.getJSONObject("endereco");
                JSONArray coord = end.getJSONArray("coord");
                LatLng latLng = new LatLng(coord.getDouble(0), coord.getDouble(1));
                JSONArray telefones = medicoObj.getJSONArray("telefone");
                String[] tels = new String[telefones.length()];
                for (int j = 0; i < telefones.length(); i++) {
                    tels[i] = telefones.get(i).toString();
                }
                Contato c = new Contato(
                        medicoObj.getString("area")
                        , medicoObj.getString("nome")
                        , end.getString("rua")
                        , Integer.parseInt(end.getString("numero"))
                        , end.getString("complemento")
                        , tels
                        , latLng
                );
                contatoList.add(c);
        }

        return contatoList;
    } catch (JSONException e) {
        e.printStackTrace();
    }
    return null;
}

Upvotes: 1

Views: 402

Answers (1)

Israel Merljak
Israel Merljak

Reputation: 241

Thanks to Liquid Penguin comment i was able to detect the problem. Since i was looking into the Adapter class for problems i wasn't noticing the repeated data coming from the JSON parser class.

It wasn't checking for duplicate data when getting data from the JSON to the array. Here comes the fixed parser code with the required verifications:

 private static ArrayList<Contato> contatoList = new ArrayList<>();
public static ArrayList<Contato> parseJSON(String jsonString){
    try {
        JSONObject jsonObject = new JSONObject(jsonString);

        JSONArray jsonArray = jsonObject.optJSONArray("medicos");

            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject medicoObj = jsonArray.getJSONObject(i);
                if (medicoObj.length() != contatoList.size()) {
                    JSONObject end = medicoObj.getJSONObject("endereco");
                    JSONArray coord = end.getJSONArray("coord");
                    LatLng latLng = new LatLng(coord.getDouble(0), coord.getDouble(1));
                    JSONArray telefones = medicoObj.getJSONArray("telefone");
                    String[] tels = new String[telefones.length()];
                    for (int j = 0; i < telefones.length(); i++) {
                        tels[i] = telefones.get(i).toString();
                    }
                    Contato c = new Contato(
                            medicoObj.getString("area")
                            , medicoObj.getString("nome")
                            , end.getString("rua")
                            , Integer.parseInt(end.getString("numero"))
                            , end.getString("complemento")
                            , tels
                            , latLng
                    );
                    if (!contatoList.contains(c))
                        contatoList.add(c);
                }
            }

        return contatoList;
    } catch (JSONException e) {
        e.printStackTrace();
    }
    return null;
}

Upvotes: 1

Related Questions