keepSync & addListenerForSingleValueEvent

2,734 views
Skip to first unread message

François Perret

unread,
Aug 25, 2015, 6:47:39 PM8/25/15
to Firebase Google Group
Hi there,

The "keepSync" feature's docs state : "Firebase synchronizes and stores a local copy of the data for active listeners."

Is a listener added with "addListenerForSingleValueEvent listener" considered as an active listener?

In that case, adding a listener in such a way should always return up to data datas, which doesn't appear to be the case.

Thanks.






Kato Richardson

unread,
Sep 3, 2015, 12:43:20 PM9/3/15
to Firebase Google Group
François,

Great to hear from you. I'm not really sure what "adding a listener in such a way should always return up to data datas" means in this context.

Would you mind including a bit of code that demonstrates your problem?

☼, Kato

--
You received this message because you are subscribed to the Google Groups "Firebase Google Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebase-tal...@googlegroups.com.
To post to this group, send email to fireba...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/firebase-talk/d5581e0e-338f-4981-9d56-395d4df624f4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

François Perret

unread,
Sep 3, 2015, 12:58:09 PM9/3/15
to fireba...@googlegroups.com
Hi K.,

Thanks for your reply.

I meant up to date datas, sorry for the typo.

Here is what I wonder:
mFirebase.child("messages").child("receivers").addListenerForSingleValueEvent(new ValueEventListener() {
@Override public void onDataChange(DataSnapshot dataSnapshot) {
// Does dataSnapshot contains all modifications until now, without /messages/receivers being “kept sync”?
}
@Override public void onCancelled(FirebaseError firebaseError) {}
});

I know the dataSnapshot would be up to date if the listener had been added using addValueEventListener() instead.
Thanks for your time.

F.


Kato Richardson

unread,
Sep 3, 2015, 1:10:10 PM9/3/15
to Firebase Google Group
Can you also explain why you're not just using addValueEventListener?

☼, Kato

François Perret

unread,
Sep 3, 2015, 1:17:21 PM9/3/15
to fireba...@googlegroups.com
Because, like a simple query, I need the value now, and find it handy not to have to remove the listener. Plus sometimes I know the value won’t change.

Quite the same thing is done in the docs https://www.firebase.com/docs/android/guide/retrieving-data.html#section-complex-queries (in "putting it all together”).

F.


Kato Richardson

unread,
Sep 3, 2015, 1:25:10 PM9/3/15
to Firebase Google Group
Hi François,

Thanks for this. Be patient with me a little longer while I get a grasp on this.

You've stated that you know the data won't change, but also that you want the latest, up to date data. You're also trying to make sure you have the latest, but not using a listener that updates whenever it changes. There may be a great reason for this, but at first glance the goal and the coding strategy seem contradictory.

Also, I don't see keepSynced() in your example code.

Again, my goal here is just to get a complete picture so I can dig in and help you generate a solution. Or, more specifically, ask someone better at offline sync the right questions to generate a solution. : )

☼, Kato

François Perret

unread,
Sep 3, 2015, 4:15:46 PM9/3/15
to fireba...@googlegroups.com
Hi Kato,

Here is a simple use case (question is in the commented code below).

  1. User 1 creates /path/{val:1}
  2. User 2 sets /path/val to 2
  3. User 1 reads /path/val (no keepSync on /path/ nor /path/val/ here)
mFirebase.child("path").child("val").addValueEventListener(new ValueEventListener() {

@Override public void onDataChange(DataSnapshot dataSnapshot) {
        int val = dataSnapshot.getValue(Integer.class); // Is val 1 or 2 here?
    }
@Override public void onCancelled(FirebaseError firebaseError) {
}
});
F.

Kato Richardson

unread,
Sep 4, 2015, 12:29:44 PM9/4/15
to Firebase Google Group
// Is val 1 or 2 here?

This depends on when this is called relative to the other operations and when and how you're calling keepSynced(). Could you please include the relevant code that's setting the value and calling keepSynced()?

François Perret

unread,
Sep 4, 2015, 1:53:05 PM9/4/15
to fireba...@googlegroups.com
Kato,

Thanks for your reply.

This is my whole point here: Is there a chance that a query to firebase (with addListenerForSingleValueEvent (I corrected my sample below, since I had used a regular listener, whose behaviour is different)) returns outdated datas, if I did *not* take care of keeping the path synced?

From what I understand of your answer, and from the behaviour I witnessed, this *is* the case, and the paths you query this way have to be keptSync in a way.

How to keep the path sync, and where and when to put the calls to keepSync(true)/keepSync(false) is not my point here, and it is no big deal.

F.





On 04 Sep 2015, at 18:29, Kato Richardson <wu...@firebase.com> wrote:

// Is val 1 or 2 here?

This depends on when this is called relative to the other operations and when and how you're calling keepSynced(). Could you please include the relevant code that's setting the value and calling keepSynced()?
On Thu, Sep 3, 2015 at 1:15 PM, François Perret <app.b...@gmail.com> wrote:
Hi Kato,

Here is a simple use case (question is in the commented code below).

  1. User 1 creates /path/{val:1}
  2. User 2 sets /path/val to 2
  3. User 1 reads /path/val (no keepSync on /path/ nor /path/val/ here)
mFirebase.child("path").child("val”).addListenerForSingleValueEvent(new ValueEventListener() {
F.

Kato Richardson

unread,
Sep 4, 2015, 2:03:06 PM9/4/15
to Firebase Google Group
Please provide a minimal repro that demonstrates the behavior and I'll be able to a) answer your question and b) see if something is not performing as expected. A lot here depends on what you mean by outdated, and the best way to explain that will be with actual code demonstrating the entire process demonstrating writing and reading the data, and comments telling us what you expected to see.

Michael Lehenbauer

unread,
Sep 4, 2015, 2:09:14 PM9/4/15
to Firebase Google Group
Hey François,

The behavior for addListenerForSingleValueEvent is:
  1. If we have cached data: raise an event with whatever we have cached (this may be stale).
  2. Send a request to the server to get the latest data.
This means that you may get stale data in your event callback.  You should get fresher data the next time you call addListenerForSingleValueEvent (since we'll have tried to update the cache).

We know this isn't ideal behavior and are looking into ways to improve it.  For now, using keepSynced() is a good approach to make sure it's as fresh as possible.

Hope this helps,
-Michael

François Perret

unread,
Sep 4, 2015, 2:57:09 PM9/4/15
to fireba...@googlegroups.com
Thank you both,

So a rule of thumb is that querying data with addListenerForSingleValueEvent implies that you keepSync’ed the queried path, in order to have the most recent remote data.

I have my answer, sorry if I wasn’t clear enough from the beginning!

F.

Evans Attafuah

unread,
Sep 6, 2015, 12:36:43 PM9/6/15
to Firebase Google Group
Hello, 

to add to this discussion my use of keep sync happens quite frequently. in my case anytime a "status update is received" <- completely related to my app. What I want to highlight is I use keep sync for specific paths [ somepath/conversation/singleChat ] and I never set it to false, so keep sync might fire multiple times for each single message, is there a better way to approach this. or an alternative async completion event for keep sync. 

Jonny Dimond

unread,
Sep 7, 2015, 2:44:16 PM9/7/15
to Firebase Google Group
I'm not sure I understand your scenario. Do you have a concrete example and code of where this is happening? keepSynced does not cause any events to fire and what you are seeing might be related to how we raise events for child added events (we will raise a child added event even if the data existed when you attach a listener...).

Jonny

GmailMe

unread,
Sep 7, 2015, 3:38:12 PM9/7/15
to fireba...@googlegroups.com
Hello Jonny,

You clearly don't understand what I mean. :) let me explain. Imagine keep sync being in a loop right? I need a way to set it to false after the data has been downloaded and am saying if keep sync had an async completion event then i would know for sure data has been downloaded.  



Sent from my iPhone 6
You received this message because you are subscribed to a topic in the Google Groups "Firebase Google Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/firebase-talk/ptTtEyBDKls/unsubscribe.
To unsubscribe from this group and all its topics, send an email to firebase-tal...@googlegroups.com.

To post to this group, send email to fireba...@googlegroups.com.

Jonny Dimond

unread,
Sep 7, 2015, 4:51:55 PM9/7/15
to Firebase Google Group
Hi Evans,

thanks for the clarification. I think I understand now what you mean. There is currently no way to be notified about keep syncs progress. You can attach a value event listener to check wether data was retrieved from the server, however the event might still contain the old data if there was no connection to the server yet. Our advise is nearly always to use a normal event listener and not a single value event listener in such cases, which will solve the issues with stale data. Performance is actually better for normal event listener than for a single event listener in a loop.

Jonny

Evans Attafuah

unread,
Sep 7, 2015, 8:40:40 PM9/7/15
to Firebase Google Group
By normal event listener, are you referring to value change event listener? 

Jonny Dimond

unread,
Sep 7, 2015, 9:03:08 PM9/7/15
to Firebase Google Group
Yes, a value listener added with addValueEventListener (or addChildEventListener) in contrast to a value listener attached with addListenerForSingleValueEvent.

François Perret

unread,
Sep 7, 2015, 9:05:38 PM9/7/15
to fireba...@googlegroups.com
Hi Evans,

There is no built-in way to be aware of the sync completion of you local cached version of a given path data and the server one.

Here are your best choices:
  • A single value listener (actually a value listener, added with addListenerForSingleValueEvent) and a keepSync on the path, which will be triggered once.
  • A normal event listener (value or child flavour, added with addValueEventListener or addChildEventListener, resp.) which might be triggered several time.
Under the hood it might be the same thing, since it is my guess that keepSync(true) implementation shouldn’t be far from just adding a listener.

Hope this helps.

F.

GmailMe

unread,
Sep 7, 2015, 9:54:28 PM9/7/15
to fireba...@googlegroups.com
Thank you all. Makes perfect sense. 


Sent from my iPhone 6

Derrick Chao

unread,
Mar 19, 2020, 12:17:25 PM3/19/20
to Firebase Google Group
Hello, regarding the snippet below - is this still the case in 2020 for addListenerForSingleValueEvent? I have found that I can't depend on a listener if my app goes to the background or the user's device goes into idle mode. 

If I need one-time fresh data from Firebase RT database 100% of the time then, am I required to use this workaround? https://stackoverflow.com/a/38129967/5147164

Thank you.

Hey François,

The behavior for addListenerForSingleValueEvent is:
  1. If we have cached data: raise an event with whatever we have cached (this may be stale).
  2. Send a request to the server to get the latest data.
This means that you may get stale data in your event callback.  You should get fresher data the next time you call addListenerForSingleValueEvent (since we'll have tried to update the cache).

We know this isn't ideal behavior and are looking into ways to improve it.  For now, using keepSynced() is a good approach to make sure it's as fresh as possible.

On Monday, September 7, 2015 at 6:54:28 PM UTC-7, Evans Attafuah wrote:
Thank you all. Makes perfect sense. 

Sent from my iPhone 6

On Sep 8, 2015, at 1:05 AM, François Perret <app....@gmail.com> wrote:

Hi Evans,

There is no built-in way to be aware of the sync completion of you local cached version of a given path data and the server one.

Here are your best choices:
  • A single value listener (actually a value listener, added with addListenerForSingleValueEvent) and a keepSync on the path, which will be triggered once.
  • A normal event listener (value or child flavour, added with addValueEventListener or addChildEventListener, resp.) which might be triggered several time.
Under the hood it might be the same thing, since it is my guess that keepSync(true) implementation shouldn’t be far from just adding a listener.

Hope this helps.

F.

To unsubscribe from this group and stop receiving emails from it, send an email to fireba...@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "Firebase Google Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/firebase-talk/ptTtEyBDKls/unsubscribe.
To unsubscribe from this group and all its topics, send an email to fireba...@googlegroups.com.

Kato Richardson

unread,
Mar 26, 2020, 1:04:45 AM3/26/20
to Firebase Google Group
Hi Derrick,

The behavior hasn't changed. If you call addListenerForSingleValueEvent while offline, it uses the local copy. If you want to make sure you get the remote copy, make sure the service is connected before you request it. A simple answer here is to just make a REST request; this is really what you're asking for; just get the value if we're online.

Alternately, if you really want the most current value, then subscribe and don't use SingleValueEvent.  Then you'll always have the latest.

☼, Kato



--

Kato Richardson | Developer Programs Eng | kato...@google.com | 775-235-8398

Derrick Chao

unread,
Mar 26, 2020, 3:10:56 PM3/26/20
to fireba...@googlegroups.com
Thanks Kato. To confirm, using subscribe would require using GCM, is that right? I was hoping to avoid incorporating that, but will look into it. 

Back to addListenerForSingleValueEvent, what do you think about the workaround outlined here? https://stackoverflow.com/questions/35454652/how-to-bypass-the-firebase-cache-to-refresh-data-in-android-app/38129967#38129967




Kato Richardson

unread,
Mar 30, 2020, 2:18:51 PM3/30/20
to Firebase Google Group
Reply all
Reply to author
Forward
0 new messages