1

As we all know Android's listview and expandablelistview recycles its view. More info: The nuance of android listview.

I've read articles and information such as the above link on how to handle that but they only give only examples on list views not on Expandablelistview (whereas getView is the only method in listview while in expandablelistview there is getGroupView and getChildView).

My expandable listview's children has or needs to have different layouts because that's necessary to achieve the application's output.

Now, my question is how to properly handle the recycling of expandable list view that inflates different layouts in its child? Such as where to put the viewHolder or convertView in my expandablelistview's getChildView method.

I followed the code below from this site in achieving a child that inflates different layouts according to its position.

Whenever I click on another group. The previous group's child recycles its view to its default thus spinner and edit text values is not being retained. I think maybe its because it inflates once again the view?

Below is my getChildView method:

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

            //layoutInflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
            //convertView = layoutInflater.inflate(R.layout.expandable_child_layout, parent, false);
        try{
            int itemType = getChildType(groupPosition, childPosition);

            switch(itemType){
            case 0:
                ViewHolder mainHolder = null;
                View v1 = null;
                if(v1 == null){

                    mainHolder = new ViewHolder();
                    v1 = View.inflate(context, R.layout.newtrip_main, null);
                    v1.setTag(mainHolder);

                    mainHolder.tripType = (Spinner) v1.findViewById(R.id.spinTripType);

                    /*TripTypeAdapter = new ArrayAdapter<String>(NewTrip.this, android.R.layout.simple_spinner_item,getResources().getStringArray(R.array.triptypes)); //selected item will look like a spinner set from XML
                    TripTypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                    tripType.setAdapter(TripTypeAdapter);*/
                    mainHolder.tripType.setOnItemSelectedListener(this);

                }//else{
                    //mainHolder = (ViewHolder) v1.getTag();
                //}
                return v1;
                //break;
            case 1:

                ViewHolder  budgetHolder = null;
                View v2 = null;
                if(v2 == null){

                    budgetHolder = new ViewHolder();
                    v2 = View.inflate(context, R.layout.newtrip_budget, null);
                    v2.setTag(budgetHolder);

                    budgetHolder.budget = (Spinner) v2.findViewById(R.id.spinBudget);
                    budgetHolder.budgetAdapter = new ArrayAdapter<String>(NewTrip.this, android.R.layout.simple_spinner_item,getResources().getStringArray(R.array.budgettype)); //selected item will look like a spinner set from XML
                    budgetHolder.budgetAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                    budgetHolder.budget.setAdapter(budgetHolder.budgetAdapter);
                    budgetHolder.budget.setOnItemSelectedListener(this);

                }

                return v2;
                //break;
            case 2:

                ViewHolder  foodHolder= null;
                View v3 = null;
                if(v3 == null){
                    foodHolder = new ViewHolder();
                    v3 = View.inflate(context, R.layout.newtrip_food, null);
                    v3.setTag(foodHolder);
                }
                return v3;
                //break;
            case 3:

                ViewHolder  accomHolder= null;
                View v4 = null;
                if(v4 == null){
                    accomHolder = new ViewHolder();
                    v4 = View.inflate(context, R.layout.newtrip_accommodation, null);
                    v4.setTag(accomHolder);

                    accomHolder.accommodation = (Spinner) v4.findViewById(R.id.spinAccommodation);

                    accomHolder.accommodationAdapter = new ArrayAdapter<String>(NewTrip.this, android.R.layout.simple_spinner_item,getResources().getStringArray(R.array.economicalAccomodation)); //selected item will look like a spinner set from XML
                    accomHolder.accommodationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                    accomHolder.accommodation.setAdapter(accomHolder.accommodationAdapter);
                    //return convertView;
                }

                return v4;
                //break;

            }
        }catch(Exception e){
            Toast toast = Toast.makeText(context, e.toString(), Toast.LENGTH_LONG);
            toast.show();
        }
            convertView.invalidate();
            return convertView;
    }

and here's the getGroupView method:

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


        convertView = View.inflate(context, R.layout.expandable_group_layout, null);
        TextView txtView = (TextView) convertView.findViewById(R.id.txt1);                 

        if(groupPosition == 0) {
          txtView.setText("   MAIN");
          txtView.setTextSize(15f);
          }
        if(groupPosition == 1) {
            txtView.setText("   BUDGET");
            txtView.setTextSize(15f);
          }
        if(groupPosition == 2) {
            txtView.setText("   FOOD");
            txtView.setTextSize(15f);
          }
        if(groupPosition == 3) {
            txtView.setText("   ACCOMMODATION");
            txtView.setTextSize(15f);
          }

        convertView.invalidate();
        return convertView;

    }
cribal48
  • 29
  • 1
  • 9

3 Answers3

0

It's exactly the same thing. Just treat the getChildView method the same way you would as the normal getView. So for your case, you'd want to do the following:

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

@Override
public int getChildTypeCount() {
    return getGroupCount();
}

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
    switch (getChildType(groupPosition, childPosition) {
    case 1:
        ViewHolder vh = null;
        if (convertView == null) {
            vh = new ViewHolder();
            //Inflate your view
            convertView.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }
        //Load any data into view
        return convertView;
    case 2:
        //Repeat for all expected types
    }
}
Ifrit
  • 6,791
  • 8
  • 50
  • 79
  • I followed your format but I'm having a null pointer exception. I'll add the error I've encountered in my question above. – cribal48 Jan 02 '15 at 15:57
  • You need to setTag of the convertView with the ViewHolder. Updated code – Ifrit Jan 02 '15 at 17:09
  • What debugging have you done? What do you think is going on? It's crashing in your `spinnerTripSelection` which seems to derive from the `onItemSelected` listener. – Ifrit Jan 02 '15 at 19:45
  • I fixed the problem with onItemSelected listener and the app does not crash or produce an error anymoe but I go back again in dealing with recycling of views. Whenever I click on another group. The previous group's child recycles its view to its default thus spinner and edit text values is not being retained. I think maybe its because it inflates once again the view? – cribal48 Jan 03 '15 at 04:59
  • Do I have to make new views in every child or case? Which view should I return? – cribal48 Jan 04 '15 at 12:49
0

To control the recycling of the child list in the expandable listview make sure that you are saving the changed data in the hash map so that you can keep track of that changed data when you scroll up or don parse the hash map data with the list and you can see the result.

nakul
  • 85
  • 5
0

I had almost the same problem, I solve it with this : https://stackoverflow.com/a/28550013/4342099.

Try to extend BaseExpandableListAdapter and override getChildTypeCount() and getChildType()

Community
  • 1
  • 1