Timon Doo
Timon Doo

Reputation: 153

Retrieve child from firebase database in android

Im trying to retrieve 2 databranches from my firebase but um getting a nullpointException and i dont know why

Here is the Database

enter image description here

The code for retrieving the cookingTime and the category

 FirebaseDatabase.getInstance().getReference().child( "recipes" )
                .addListenerForSingleValueEvent( new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                            /*Recipe recipe = snapshot.getValue( Recipe.class );*/

                            DatabaseReference recipes = FirebaseDatabase.getInstance().getReference("recipes");
                            Recipe recipe_test = snapshot.child( "recipe_1" ).getValue(Recipe.class);



                            category.setText( recipe_test.getCategory() );
                            cookinTime.setText( recipe_test.getCookingtime() );


                        }
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                    }
                } );
    }

the recipe class

package com.example.myapplicationdatatest;

import java.lang.reflect.Array;
import java.util.List;
import java.util.Map;

public class Recipe {

    private String category;
    private long cookingtime;
    private String description;
    private Map<String, Object> amountOfIngredients;
    private String nameOfRecipe;
    private Map<String, Object> Ingredients;

    public Recipe() {};



       public Recipe(String category, long cookingtime, String description,Map<String, Object> amountOfIngredients, String nameOfRecipe, Map<String, Object> Ingridients) {
            this.category=category;
            this.cookingtime=cookingtime;
            this.description=description;
            this.amountOfIngredients=amountOfIngredients;
            this.nameOfRecipe=nameOfRecipe;
            this.Ingredients=Ingridients;
        }

        public String getCategory() {
            return category;
        }

        public String getCookingtime() {
            long ct = cookingtime;
            String result = String.valueOf( ct );
            return result;
        }

        public String getDescription() {
            return description;
        }

        public Map<String, Object> getAmountOfIngredients() {
            return amountOfIngredients;
        }

        public String getNameOfRecipe() {
            return nameOfRecipe;
        }

        public Map<String, Object> getIngredients() {
            return Ingredients;
        }




    }

and the exception

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.myapplicationdatatest, PID: 20846
    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.myapplicationdatatest.Recipe.getCategory()' on a null object reference
        at com.example.myapplicationdatatest.MainActivity$1.onDataChange(MainActivity.java:73)
        at com.google.firebase.database.Query$1.onDataChange(com.google.firebase:firebase-database@@19.1.0:179)
        at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@19.1.0:75)
        at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@19.1.0:63)
        at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@19.1.0:55)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
I/Process: Sending signal. PID: 20846 SIG: 9
Disconnected from the target VM, address: 'localhost:8611', transport: 'socket'

I createdd a recipe class for the database which works, because i tried it before when there was only one recipe in the database

thx for your help

Upvotes: 1

Views: 601

Answers (2)

Frank van Puffelen
Frank van Puffelen

Reputation: 598668

You're listening to recipes and then looping over the children under it. That means in the first iteration snapshot will point to recipe_1 already, and you don't need to subaddress for that child anymore:

FirebaseDatabase.getInstance().getReference().child( "recipes" )
    .addListenerForSingleValueEvent( new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                Recipe recipe_test = snapshot.getValue( Recipe.class );

If you want to explicitly get certain recipes, get rid of the loop and use direct child("...") access:

FirebaseDatabase.getInstance().getReference().child( "recipes" )
    .addListenerForSingleValueEvent( new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Recipe recipe1 = dataSnapshot.child("recipe_1").getValue( Recipe.class );
            Recipe recipe2 = dataSnapshot.child("recipe_2").getValue( Recipe.class );

Upvotes: 2

Yash
Yash

Reputation: 3576

When using .getValue(), note that:

This method is used to marshall the data contained in this snapshot into a class of your choosing. The class must fit 2 simple constraints:

  1. The class must have a default constructor that takes no arguments
  2. The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized

I suggest that after defining the class variable just do Alt+Insert in Android Studio to generate the public getters-setters.

Moreover, as pointed by Frank in his answer, you will receive all the recipes under "recipes" by doing this:

FirebaseDatabase.getInstance().getReference().child( "recipes" )
    .addListenerForSingleValueEvent( new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                Recipe recipe_test = snapshot.getValue( Recipe.class );
            }
        });

Now inside the for-each loop you need to use the values. For example when you want snapshot having key = "recipe_2" you need to do this:

if( snapshot.getKey().equals("recipe_2")) {
    //do your stuff
}

Full code:

FirebaseDatabase.getInstance().getReference().child( "recipes" )
    .addListenerForSingleValueEvent( new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                if( snapshot.getKey().equals("recipe_2")) {
                     //do your stuff           
                     Recipe recipe_2 = snapshot.getValue( Recipe.class );
                }
            }
        });

Upvotes: 2

Related Questions