ExpandableListView crashes when some groups are empty

I'm working on an Android app which implements a navigation drawer with an ExpandableListView menu, in this view some elements are supposed to have childs and others have to do an action when clicked, with no childs. My problem here is that I have some random crashing and I can't understand what may be causing it. Here's the error code:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.toptainer.www, PID: 9722 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference at com.example.nignog.toptainer.ExpandableListAdapter.getChildView(Success.java:377)

App will mostly crash when clicking an empty group and then clicking on a group with children, though it won't always crash the app.

Anyway here's my code:

First of all here's my adapter:

class ExpandableListAdapter extends BaseExpandableListAdapter {

    private Context _context;
    private List<String> _listDataHeader;
    private HashMap<String, List<String>> _listDataChild;

    public ExpandableListAdapter(Context context, List<String> listDataHeader,
                                 HashMap<String, List<String>> listChildData) {
        this._context = context;
        this._listDataHeader = listDataHeader;
        this._listDataChild = listChildData;
    }

    @Override
    public Object getChild(int groupPosition, int childPosititon) {
        return this._listDataChild.get(this._listDataHeader.get(groupPosition))
                .get(childPosititon);
    }

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

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

        if(getChildrenCount(groupPosition)>1){

        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.menu_item, null);
        }

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

        txtListChild.setText(childText);
        }
        else{
            LayoutInflater infalInflater = (LayoutInflater) this._context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.empty_item, null);
        }
        return convertView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        if(this._listDataChild.get(this._listDataHeader.get(groupPosition))
                 != null){
            return this._listDataChild.get(this._listDataHeader.get(groupPosition))
                    .size();
        }
        return 1;

    }

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

    @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 infalInflater = (LayoutInflater) this._context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.menu_item, null);
        }

        TextView lblListHeader = (TextView) convertView
                .findViewById(R.id.textoOpcion);
        lblListHeader.setTypeface(null, Typeface.BOLD);
        lblListHeader.setText(headerTitle);
        ImageView icon = (ImageView) convertView.findViewById(R.id.Icono);

        int[] iconos = {R.drawable.ic_user, R.drawable.ic_camion, R.drawable.ic_box, R.drawable.ic_file, R.drawable.ic_report, android.R.drawable.ic_delete};
        icon.setImageResource(iconos[groupPosition]);

        if(groupPosition == 0) {
            convertView.setBackgroundColor(Color.BLACK);
            lblListHeader.setTextColor(Color.WHITE);
        }
        else {
            convertView.setBackgroundColor(Color.WHITE);
        }


        return convertView;
    }

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

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        if(getChildrenCount(groupPosition)!=1)return true;
        return false;
    }
}

Activity's onCreate method:

android.support.v7.app.ActionBar ab = getSupportActionBar();
        ab.setHomeAsUpIndicator(R.drawable.hamburger_button);
        ab.setDisplayHomeAsUpEnabled(true);

        expandableList= (ExpandableListView) findViewById(R.id.left_drawer);


        mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
        mActivityTitle = getTitle().toString();
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
        String[] accionesMenu = {getSharedPreferences("Data",Context.MODE_PRIVATE).getString("Usuario", "NOUSER"), "Orden de viaje Emitidas", "Órdenes de viaje en Descarga","Órdenes de viaje en Tránsito","Órdenes de viaje Entregadas","Órdenes de viaje en Carga", "Órdenes de transporte","Guías pendientes", "Reporte", "Desconectar"};
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        expandableList = (ExpandableListView) findViewById(R.id.left_drawer);
        prepareListData();

        mMenuAdapter = new ExpandableListAdapter(this, listDataHeader,   listDataChild);

        // setting list adapter
        expandableList.setAdapter(mMenuAdapter);

        expandableList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v,
                                        int groupPosition, long id) {

                boolean booleano = expandableList.isGroupExpanded(groupPosition);
                for(int i =0;  i<5; i++){
                if(expandableList.isGroupExpanded(i)) expandableList.collapseGroup(i);}

                if(!booleano) expandableList.expandGroup(groupPosition);

                if (groupPosition == 3) startGuiasActivity();

                if (groupPosition == 5) {
                    startLoginActivity();
                }
                return true;
            }
        });

        expandableList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {

            @Override
            public boolean onChildClick(ExpandableListView parent, View v,
                                        int groupPosition, int childPosition, long id) {
                if (groupPosition == 1) {
                    if (childPosition == 0) startOrdenesDeViajeActivity();
                    if (childPosition == 1) startOrdenesDeViajeDescargaActivity();
                    if (childPosition == 2) startOrdenesDeViajeTransitoActivity();
                    if (childPosition == 3) startOrdenesDeViajeEntregadasActivity();
                    if (childPosition == 4) startOrdenesDeViajeCargaActivity();
                }
                return false;
            }
        });

And here is my prepareData method:

private void prepareListData() {
        listDataHeader = new ArrayList<String>();
        listDataChild = new HashMap<String, List<String>>();

        // Adding data header
        listDataHeader.add(getSharedPreferences("Data", Context.MODE_PRIVATE).getString("Usuario", "NOUSER"));
        listDataHeader.add("Órdenes de Viaje");
        listDataHeader.add("Órdenes de Transporte");
        listDataHeader.add("Guías Pendientes");
        listDataHeader.add("Reporte");
        listDataHeader.add("Desconectar");

        // Adding child data
        List<String> heading1= new ArrayList<String>();
        heading1.add("Emitidas");
        heading1.add("En proceso de Descarga");
        heading1.add("En tránsito");
        heading1.add("Entregadas");
        heading1.add("En proceso de Carga");


        listDataChild.put(listDataHeader.get(1), heading1);

    }

Any help woud be greatly appreciated.

Upvotes: 1

Views: 1364

Answers (1)

Shadab Ansari
Shadab Ansari

Reputation: 7070

In your getChildView()

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

txtListChild is null somehow. That's why you are getting NullPointerException.

Why ?

The reason is that you are inflating different layouts for different situations - R.layout.menu_item for group with children and R.layout.empty_item view for group having no child

but you are inflating the view only if

if (convertView == null) 

and in that case suppose the last view inflated is R.layout.empty_item and if the next item is group with no child, the if (convertView == null) will return false and hence your R.layout.menu_item will not be inflated and it will reuse R.layout.empty_item . And in that case you will not have your textView (which will be null). This will give you NullPointerException.

Solution

You have to change the 2 layouts by making their parent layout different. Let's say the parent layout for R.layout.empty_item is RelativeLayout and for R.layout.menu_item is LinearLayout. Change your getView() -

     if(getChildrenCount(groupPosition)>1){
                if(converterView == null || converterView.getClass() == RelativeLayout.class){
                    converterView = inflater.inflate(R.layout.menu_item, null);

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

        txtListChild.setText(childText);
                }
            }
            else{
                if(converterView == null || converterView.getClass() == LinearLayout.class){
                    converterView = inflater.inflate(R.layout.empty_item, null);
                }
            }

return converterView;

Hope this will help !

Upvotes: 2

Related Questions