1

I am adding a listener to a node within my database as follows:

ref = myDB.getReference("testNode/" + uID);

...


ref.addValueEventListener(new ValueEventListener() {
   @Override
   public void onDataChange(DataSnapshot dataSnapshot) {
     for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
        Log.d("PROFILE", singleSnapshot.getKey());
     }
   }

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

Here is my database structure:

   "testNode" : {
     "ffggg@gmailcom" : {
       "kcd8huka0bha6md22nh1k5enj0" : 1484814690039,
       "vd4vk67n2gb7qgpol0jp8gee62" : 1484814727049
     },
     "test22@gmailcom" : {
       "8o93lpc5clhrsrst852nfm2g75" : 1484815514788,
       "a18g2u5h525nqthpqsn6askp75" : 1484814852458
     }
   }

As you can see above I have a Log for testing, the Log prints as follows:

01-19 08:44:57.547 17531-17531/com.firebase.android D/PROFILE: ffggg@gmailcom 01-19 08:44:57.547 17531-17531/com.firebase.android D/PROFILE: test22@gmailcom 01-19 08:45:15.446 17531-17531/com.firebase.android D/PROFILE: 8o93lpc5clhrsrst852nfm2g75 01-19 08:45:15.446 17531-17531/com.firebase.android D/PROFILE: a18g2u5h525nqthpqsn6askp75 01-19 08:45:15.448 17531-17531/com.firebase.android D/PROFILE: ffggg@gmailcom 01-19 08:45:15.449 17531-17531/com.firebase.android D/PROFILE: test22@gmailcom 01-19 08:45:15.587 17531-17531/com.firebase.android D/PROFILE: 8o93lpc5clhrsrst852nfm2g75 01-19 08:45:15.587 17531-17531/com.firebase.android D/PROFILE: a18g2u5h525nqthpqsn6askp75 01-19 08:45:15.588 17531-17531/com.firebase.android D/PROFILE: ffggg@gmailcom 01-19 08:45:15.588 17531-17531/com.firebase.android D/PROFILE: test22@gmailcom

Now assuming uID is test22@gmailcom (and i have checked the string is not null or empty) I should only get test22@gmailcom's children. Yet here I get all nodes under ref (but not their children, unless the node is uID). I dont want this because then I download lots of unnecessary data if I had thousands upon thousands of records.

Am i doing something wrong or was the Listners implemented like this by firebase?

Update 1

When I open the application from the app drawer it will get the correct children of the node I want. However, when I go to another activity inside of this activity I add a child to the node I am listening on in the other class and then go back to the class which is listening on that node I get the weird output.

Here is the code for the other activity where I add to the node:

pullNewImage = myDB.getReference("testNode");
pullNewImage.child(uID).child(randomName).setValue(ServerValue.TIMESTAMP);

Update 2

My updated listener code:

 //global var

 ValueEventListener profileListener = null;

//....

profileListener = ref.child(userEmail).addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
                            Log.d("PROFILE", singleSnapshot.getKey());
                        }
                    }

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


//...
 @Override
        public void onStop() {
            super.onStop();
            if (mAuthListener != null) {
                auth.removeAuthStateListener(mAuthListener);
            }
            if(profileListener != null)
                ref.removeEventListener(profileListener);

        }

5 Answers5

1

Use ref = myDB.getReference("testNode").child(uID);

EDIT:

Since you're saying the problem is when you change activities, you might not be stopping the listener.

Add a ValueEventListener: ValueEventListener profileListener = null; and remove the Thread. Then set your listener to the ValueEventListener:

profileListener = ref.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
        Log.d("PROFILE", singleSnapshot.getKey());
    }
}

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

Then override the onStop() method:

@Override
public void onStop() {
    super.onStop();

    if(profileListener != null)
        ref.removeEventListener(profileListener);
}

EDIT 2:

Still not sure why the above does not work, but you can also give this a shot:

The following assumes DatabaseReference ref = FirebaseDatabase.getInstance().getReference("testNode");

Query profileQ = ref.orderByKey().equalTo(userEmail);
profileQ.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
        Log.d("PROFILE", singleSnapshot.getKey());
    }
}

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

If that works, you'd have to replace the ValueEventListener with the Queue (Queue is inherited from ValueEventListener). Since it's dealing with a UID, it'd only return one... But I'd be surprised if this works while the other methods did not.

Aubtin Samai
  • 1,281
  • 13
  • 24
  • I have already tried this, and just tried it again to be sure. It doesn't work. When I launch the application the children under the correct node will be printed and nothing more as I want. Its when I add to the node from another activity that I get the weird output mentioned in the block quote above – TerribleCoderSad Jan 19 '17 at 09:04
  • Why do you have the listener in a Thread? The listener runs Async.. I'd remove it unless you have some other reason for it. – Aubtin Samai Jan 19 '17 at 09:10
  • Also, do you want to keep listening for changes, or just want to get the data once? – Aubtin Samai Jan 19 '17 at 09:11
  • Ah yes I forgot it runs Async. I removed it and doesn't change anything. Same bug. Also I want to keep listening – TerribleCoderSad Jan 19 '17 at 09:16
  • Try what I added above, it'll stop the listener once you leave the activity, which is good practice to clean it up. Also, if you're looking to just fetch the info once, you can just change your current addValueEventListener to addSingleValueEventListener. – Aubtin Samai Jan 19 '17 at 09:25
  • This doesn't seem to work, other node data is still being printed. but this time only once of course – TerribleCoderSad Jan 19 '17 at 09:36
  • I'm a little confused now.. Does it ever fetch the data correctly? I thought you said in the first comment it gets it correctly the first time until you go to another activity. – Aubtin Samai Jan 19 '17 at 09:36
  • Could you post more of your code, I feel like something else is going on if none of these solutions work? – Aubtin Samai Jan 19 '17 at 09:38
  • When I launch the application the data is pulled correctly. Now I go to another activity inside of this activity I add something to the node (the node that the other class was listening on). When I go back to that class it prints weird – TerribleCoderSad Jan 19 '17 at 09:39
  • Is what you're adding to the node working correctly (can you add that code to your question)? Can you add the above code (where it sets the ValueEventListener to the listeners) and the onStop() to all the activities that fetch from that node? Cleaning the listeners is also good practice. – Aubtin Samai Jan 19 '17 at 09:52
  • The code honestly looks fine to me, I still think there is something else in your code that is causing this. I'd have to take a look at all of it to pinpoint it... – Aubtin Samai Jan 19 '17 at 10:42
  • All of the code I provided above is everything I have relating to adding to the node and listening on the node. Is there any other way I can send an object from class A to class B and when class B receives it something is done? I need to implement it in a way though so that class B is always listening for an incoming object. – TerribleCoderSad Jan 19 '17 at 10:52
  • You could possibly try using an interface and use it in the other class as a callback when you send the object – Aubtin Samai Jan 19 '17 at 11:11
  • I added another thing you could try in my answer using Query. – Aubtin Samai Jan 19 '17 at 11:11
  • So the code you provided gives me just the node. No children. It prints the node key but no children – TerribleCoderSad Jan 19 '17 at 11:30
  • The data snapshot is `testNode` if I do `Toast.makeText(getActivity(), "key is " + dataSnapshot.getKey(), Toast.LENGTH_SHORT).show();` – TerribleCoderSad Jan 19 '17 at 11:33
  • I modified your code abit and did this, now it works i think anyway. Any idea why this works? http://pastebin.com/5cbv6nAv – TerribleCoderSad Jan 19 '17 at 11:39
  • Even though it works, I am always pulling `testNode` which I don't/never wanted to do because this means that I'm still downloading unnecessary information such as other user info. Is there anyway it can be changed to just download the correct child? or could you explain this interface idea? which I feel could be better anyway because then I can get rid of the database wait latency. I could create another question and ask it if you agree? Because you know quite well what I want to achieve now – TerribleCoderSad Jan 19 '17 at 11:46
  • You could use a ChildEventListener to only get the children of the node instead of the ValueEventListener. – Aubtin Samai Jan 19 '17 at 17:41
  • Is your class A and class B referring to two separate activities? What are you trying to send between the two classes that you want to be listening for the changes? – Aubtin Samai Jan 19 '17 at 17:42
  • Activity A is a fragment, Activity B is a fragment I am trying to send a Java class object that I made. Is it possible to use interface callbacks when Activity A exists but Activity B (the fragment) is destroyed? Activity A needs to send the data to Activity B – TerribleCoderSad Jan 20 '17 at 10:05
  • You could try using Extras to pass information between Fragments and their holding activity (http://stackoverflow.com/questions/16036572/how-to-pass-values-between-fragments). You can pass the main aspects of it through the Bundle, or you can use a Parcelable (it's slower than Serializable, but for one object it doesn't really matter). You could also convert the object to Gson (which would be sent as a String), and then change it back after (http://stackoverflow.com/questions/4249897/how-to-send-objects-through-bundle). – Aubtin Samai Jan 21 '17 at 08:16
0

To retrieve data one shot, use the following:

ref.addListenerForSingleValueEvent(
                    new ValueEventListener() {
                        @Override
                        public void onDataChange(DataSnapshot dataSnapshot) {
    }});
0

try changing the reference and listener like this:

ref = myDB.getReference().child("testnode");

or

ref = mDB.getReference("testnode");

and if you want to keep listening to the node ONLY than use "addValueEventListener" otherwise use "addListenerForSingleValueEvent".

and change the code where you attach the listener to refer the child node.

ref.child(uid).addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
                        Log.d("PROFILE", singleSnapshot.getKey());
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {}
            });
Mohammed Junaid
  • 1,362
  • 14
  • 18
0

your data in firebase is not sync ,if you have enabled persistance mode , disable it in your code

FirebaseDatabase.getInstance().setPersistenceEnabled(false);

Firebase Offline Capabilities

Varun Chaudhary
  • 370
  • 4
  • 19
0

I was getting wrong value for chat count (i.e. it always gives me total count of chat instead of unread message count )
I just done FirebaseDatabase.getInstance().setPersistenceEnabled(false); and my problem solved

Faysal Ahmed
  • 7,501
  • 5
  • 28
  • 50
Sayali
  • 132
  • 1
  • 5