2

I've traced my code to the root cause of my crashes and apparently this constructor is unable to update the variables of the class. I am getting null pointer exception when I'm trying to get data from this class. You can safely assume that the record is already in the database and all it has to do is just get the data and place it in the class/object. I simply want to get the name for now because I'm testing if the object is still null or not.

Database structure

class Saver{
    private String name;
// constructor of Saver class
public Saver(final String uid) {
        Log.d("Saver.java","Reached here"); // this works
        FirebaseDatabase.getInstance().getReference().addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(final DataSnapshot dataSnapshot) {
                Log.d("Saver.java", "OnDataChange"); // does not work
                if(dataSnapshot.hasChild("users/" + uid)){
                    LoadRecord(dataSnapshot, uid);
                }
                else{
                    // set a new record into the database
                    FirebaseDatabase.getInstance().getReference().child("users/" + uid).setValue(CreateNewRecord(FirebaseAuth.getInstance().getCurrentUser())).addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            if(task.isSuccessful()){
                                LoadRecord(dataSnapshot, uid);
                            }
                            else{
                                Log.e("Saver.java","Failed to set record in database");
                            }
                        }
                    });
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                  Log.e("LifeSaver.java","Error: " + databaseError.getMessage());
            }
        });
    }

// This function loads the data into the object
private void LoadRecord(DataSnapshot dataSnapshot, String uid){
        Log.d("LifeSaver.java","Uid:"+uid);
        // load the existing record in the database
        Saver temp = dataSnapshot.child("users/" + uid).getValue(Saver.class);
        setName(temp.getName());
    }
}
public void setName(String name) {
    this.name = name;
}
private Saver CreateNewRecord(FirebaseUser firebaseUser){
    Saver saver = new Saver ();
    saver.setName(firebaseUser.getDisplayName());
    Log.d("saver","saver name: " + saver.getName());
    return continuLifeUser;
}

Obviously the function onDataChange will not run until something changed on the database.

  1. How can I manually trigger this function, if possible?
  2. Should I have a DataSnapshot that has the children of this node? If so, how? (show code please so I can visualize what you are explaning)
  3. Is there a better way of doing this?

Edit 1: Here's the logcat statements from the constructor that should have called the FirebaseDatabase:

D/Saver.java: Reached here with hA4hZrBieISwMOZaMYe7m6K5tpI3
I/DynamiteModule: Considering local module com.google.android.gms.firebase_database:4 and remote module com.google.android.gms.firebase_database:6
I/DynamiteModule: Selected remote version of com.google.android.gms.firebase_database, version >= 6
I/art: DexFile_isDexOptNeeded failed to open oat file '/data/dalvik-cache/x86_64/data@data@com.google.android.gms@app_chimera@m@00000004@DynamiteModulesC_GmsCore_prodlmp_alldpi_release.apk@classes.dex' for file location '/data/data/com.google.android.gms/app_chimera/m/00000004/DynamiteModulesC_GmsCore_prodlmp_alldpi_release.apk': Failed to open oat filename for reading: No such file or directory
D/Saver.java: Ended here
D/LoginAct.java: Name: null
CraftedGaming
  • 499
  • 7
  • 21

3 Answers3

1

For getting all the names from all users under users node, please use the following code:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("users");
ValueEventListener eventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for(DataSnapshot ds : dataSnapshot.getChildren()) {
            String name = ds.child("name").getValue(String.class);
            Log.d("TAG", name);
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
};
usersRef.addListenerForSingleValueEvent(eventListener);

The output will be:

Michael Ong
//other names

If you want to get only the name of a particular user, please use the following code:

FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
String uid = firebaseUser.getUid();

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child("users").child(uid);
ValueEventListener eventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        String name = dataSnapshot.child("name").getValue(String.class);
        Log.d("TAG", name);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}
};
uidRef.addListenerForSingleValueEvent(eventListener);

The output will be only a single record:

Michael Ong
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • This code is somewhat identical to my version only that my version has `dataSnapshot.hasChild("users/" + uid)`. I tried your code but again the listener does not run at all. – CraftedGaming Oct 31 '17 at 08:27
  • Have you changed the permissions to `true` in your Firebase Console? Is there any error in your logcat? – Alex Mamo Oct 31 '17 at 12:21
  • if you're referring to the rules, I've set `.read` and `.write` to `auth !=null`. Regarding the error, I've updated the question with a starting debug statement from my constructor and the closing debug statement from my constructor. – CraftedGaming Nov 01 '17 at 01:36
  • Can share us your build.gradle file? It seems to be an error from your Google Play Services. – Alex Mamo Nov 01 '17 at 06:19
  • Added both `build.gradle` files – CraftedGaming Nov 01 '17 at 07:06
1

I resolved the problem by having a loading screen. I should have remembered that the call was Async and that it needed a receiver to call the function that will place the data before moving on to the next activity.

private interface OnGetDataListener {
    void onSuccess(DataSnapshot dataSnapshot);
    void onFailure();
}

Here's a small code for the listener that you'll have to implement when you're calling the database to get the data. You can check for other posts similar to this one.

CraftedGaming
  • 499
  • 7
  • 21
0

Hi first you should add data to database , then only it will work . Looks like there is no data available in Firebase.Just add a key value pair in firebase database , then it will be triggered.

FirebaseDatabase.getInstance().getReference().child("users/" + uid).addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(final DataSnapshot dataSnapshot) {
            Log.d("Saver.java", "OnDataChange"); // does not work
            if(dataSnapshot!=null){
                LoadRecord(dataSnapshot);
            }
            else{
                // set a new record into the database
                FirebaseDatabase.getInstance().getReference().child("users/" + uid).setValue(CreateNewRecord(FirebaseAuth.getInstance().getCurrentUser())).addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        if(task.isSuccessful()){
                            LoadRecord(dataSnapshot);
                        }
                        else{
                            Log.e("Saver.java","Failed to set record in database");
                        }
                    }
                });
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
              Log.e("LifeSaver.java","Error: " + databaseError.getMessage());
        }
    });
}
   // Load record should be like this...
   private void LoadRecord(DataSnapshot dataSnapshot){
    Log.d("LifeSaver.java","Uid:"+uid);
    // load the existing record in the database
    Saver temp = dataSnapshot.getValue(Saver.class);
    setName(temp.getName());
}

}

Shanmugam
  • 301
  • 1
  • 10
  • Like I said, it's safe to assume that there's data on the database. Because there is data on the database and I can see that there's data there. I just need to retrieve it. – CraftedGaming Oct 30 '17 at 09:15
  • don't put it in constructor , try separately.If data is there then it should work. – Shanmugam Oct 30 '17 at 09:33
  • and also add listener for /users so that if new user is added it will be invoked. – Shanmugam Oct 30 '17 at 09:35
  • placed it on another function but it still prints out a null pointer exception when I'm trying to log the name – CraftedGaming Oct 30 '17 at 09:56
  • i made change to query , you have use like this to check...if the user is not there it will return null , then create new user. – Shanmugam Oct 30 '17 at 10:07
  • Problem is the ValueEventListener's functions does not get triggered. How can I trigger it? – CraftedGaming Oct 31 '17 at 00:59
  • you can create object , so that it will trigger automatically Saver saver = new Saver("xxxxxx");//pass userId in constructor – Shanmugam Oct 31 '17 at 08:34
  • I do call it using my constructor with the id being passed in. It's not just working like it's suppose to. Check this reference https://stackoverflow.com/questions/38470948/firebase-addvalueeventlistener-not-being-triggered – CraftedGaming Oct 31 '17 at 08:40
  • In that case simply call in onCreate(); no need to put it in class then – Shanmugam Oct 31 '17 at 08:44
  • use the updated query i have sent.The main thing is database reference , plz provide correct db ref. – Shanmugam Oct 31 '17 at 08:47
  • It won't run at all even with your code. `continulife.firebaseio.com`, the database reference – CraftedGaming Oct 31 '17 at 09:03