ExpandableListView with Maps of objects

  android, expandablelistview, firebase, hashmap, java

I have read from Firebase the following JSON:

"categorias" : {
    "Telas de Hogar" : {
      "descripcion" : "",
      "estado" : "invisible",
      "nombre" : "Telas de Hogar",
      "paginas" : {
        "Loneta" : {
          "descripcion" : "",
          "estado" : "invisible",
          "nombre" : "Loneta",
          "productos" : {
            "0000-0001" : {
              "numero" : "0000-0001"
            },
            "0000-0002" : {
              "numero" : "0000-0002"
            },
            "0000-0003" : {
              "numero" : "0000-0003"
            },
            "0000-0004" : {
              "numero" : "0000-0004"
            }
          }
        }
      },
      "productos" : {
        "0000-0001" : {
          "numero" : "0000-0001"
        },
        "0000-0002" : {
          "numero" : "0000-0002"
        },
        "0000-0003" : {
          "numero" : "0000-0003"
        },
        "0000-0004" : {
          "numero" : "0000-0004"
        },
        "0000-0005" : {
          "numero" : "0000-0005"
        },
        "0000-0006" : {
          "numero" : "0000-0006"
        }
      }
    }
  }

And I have assigned it to a java class with the following structure:

public class Category {
    private String nombre;
    private String descripcion;
    private String estado;
    private Map<String, ProductReference> productos;
    private Map<String, Page> paginas;

    public Category(){}

    public Category(String nombre) {
        this.nombre = nombre;
        this.descripcion = "";
        this.estado = "";
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getDescripcion() {
        return descripcion;
    }

    public void setDescripcion(String descripcion) {
        this.descripcion = descripcion;
    }

    public String getEstado() {
        return estado;
    }

    public void setEstado(String estado) {
        this.estado = estado;
    }

    public Map<String, ProductReference> getProductos() {
        return this.productos;
    }

    public void setProductos(Map<String, ProductReference> productos) {
        this.productos = productos;
    }

    public Map<String, Page> getPaginas() {
        return this.paginas;
    }

    public void setPaginas(Map<String, Page> paginas) {
        this.paginas = paginas;
    }

    @Override
    public String toString() {
        return nombre;
    }
}

Now what I want is to display categorias and their paginas in a ExpandableListView. I have managed to display the object categoria in the GroupView, but when I try to assign the list of pages to the ChildView I have this error:

java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.Map.size()' on a null object reference
        at com.example.tejidospulido_app.Presentador.Adapter.AdapterCategories.getChildrenCount(AdapterCategories.java:42)...

The Fragment that the ExpandedListView belongs to is this:

public class MenuFragment extends Fragment {

    private static final String TAG = "Menu";

    private ExpandableListView exp_list_view;
    private ArrayList<Category> list_categories;
    private HashMap<String, Map<String, Page>> list_pages;
    private AdapterCategories adapter;

    public MenuFragment(){
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_menu, container, false);
        setViews(view);
        return view;
    }

    private void setViews(View view) {
        list_categories = new ArrayList<>();
        list_pages = new HashMap<>();
        exp_list_view = (ExpandableListView) view.findViewById(R.id.exp_list_view);

        adapter = new AdapterCategories(list_categories, list_pages);

        handleChargeCategoryList();
    }

    public void handleChargeCategoryList() {
        FirebaseDatabase.getInstance().getReference().child("categorias").addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                list_categories.clear();
                for (DataSnapshot snapshot : dataSnapshot.getChildren()){
                    Category c = snapshot.getValue(Category.class);
                    list_categories.add(c);
                    list_pages.put(c.getNombre(), c.getPaginas());
                    adapter = new AdapterCategories(list_categories, list_pages);
                    exp_list_view.setAdapter(adapter);
                }
            }

            @Override
            public void onCancelled(DatabaseError error) {
                // Failed to read value
                Toast.makeText(getContext(), error.getMessage(), Toast.LENGTH_LONG).show();
            }
        });

    }
}

And the Adapter:

public class AdapterCategories extends BaseExpandableListAdapter {

    private ArrayList<Category> list_categories;
    private HashMap<String, Map<String, Page>> list_pages;

    public AdapterCategories(ArrayList<Category> categoryList, HashMap<String, Map<String, Page>> list_pages){
        this.list_categories = categoryList;
        this.list_pages = list_pages;
    }

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

    @Override
    public int getChildrenCount(int groupPosition) {
        return list_pages.get(list_categories.get(groupPosition).getNombre()).size();
    }

    @Override
    public Category getGroup(int groupPosition) {
        return list_categories.get(groupPosition);
    }

    @Override
    public Page getChild(int groupPosition, int childPosition) {
        return list_pages.get(list_categories.get(groupPosition).getNombre()).get(childPosition);
    }

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

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

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

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        convertView = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
        TextView textView = convertView.findViewById(android.R.id.text1);
        //Initialize string
        String categoryName = getGroup(groupPosition).getNombre();
        textView.setText(categoryName);
        textView.setTypeface(null, Typeface.BOLD);
        textView.setTextColor(Color.BLACK);
        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        convertView = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_selectable_list_item, parent, false);
        TextView textView = convertView.findViewById(android.R.id.text1);
        //Initialize string
        String pageName = getChild(groupPosition, childPosition).getNombre();
        textView.setText(pageName);
        textView.setTextColor(Color.BLACK);

        textView.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(parent.getContext(), pageName, Toast.LENGTH_SHORT).show();
            }
        });
        return convertView;
    }

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

This is the result if I debug with a breakpoint at the getChild() function.

Source: Android Questions

LEAVE A COMMENT