Whenever I use addListenerForSingleValueEvent
with setPersistenceEnabled(true)
, I only manage to get a local offline copy of DataSnapshot
and NOT the updated DataSnapshot
from the server.
However, if I use addValueEventListener
with setPersistenceEnabled(true)
, I can get the latest copy of DataSnapshot
from the server.
Is this normal for addListenerForSingleValueEvent
as it only searches DataSnapshot
locally (offline) and removes its listener after successfully retrieving DataSnapshot
ONCE (either offline or online)?
By enabling persistence, any data that the Firebase Realtime Database client would sync while online persists to disk and is available offline, even when the user or operating system restarts the app. This means your app works as it would online by using the local data stored in the cache.
The limit you're referring to is the limit for the number of concurrently connected users to Firebase Realtime Database on the free Spark plan. Once you upgrade to a payment plan, your project will allow 200,000 simultaneously connected users.
You get all the no-cost Firebase features (Analytics, the Notifications composer, Crashlytics, and so on) and generous amounts of our paid infrastructure features. However, if you exceed your Spark plan resources in a calendar month, your app will be shut off for the remainder of that month.
Update (2021): There is a new method call (get
on Android and getData
on iOS) that implement the behavior you'll like want: it first tries to get the latest value from the server, and only falls back to the cache when it can't reach the server. The recommendation to use persistent listeners still applies, but at least there's a cleaner option for getting data once even when you have local caching enabled.
The Firebase client keeps a copy of all data you're actively listening to in memory. Once the last listener disconnects, the data is flushed from memory.
If you enable disk persistence in a Firebase Android application with:
Firebase.getDefaultConfig().setPersistenceEnabled(true);
The Firebase client will keep a local copy (on disk) of all data that the app has recently listened to.
Say you have the following ValueEventListener
:
ValueEventListener listener = new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { System.out.println(snapshot.getValue()); } @Override public void onCancelled(FirebaseError firebaseError) { // No-op } };
When you add a ValueEventListener
to a location:
ref.addValueEventListener(listener); // OR ref.addListenerForSingleValueEvent(listener);
If the value of the location is in the local disk cache, the Firebase client will invoke onDataChange()
immediately for that value from the local cache. If will then also initiate a check with the server, to ask for any updates to the value. It may subsequently invoke onDataChange()
again if there has been a change of the data on the server since it was last added to the cache.
addListenerForSingleValueEvent
When you add a single value event listener to the same location:
ref.addListenerForSingleValueEvent(listener);
The Firebase client will (like in the previous situation) immediately invoke onDataChange()
for the value from the local disk cache. It will not invoke the onDataChange()
any more times, even if the value on the server turns out to be different. Do note that updated data still will be requested and returned on subsequent requests.
This was covered previously in How does Firebase sync work, with shared data?
The best solution is to use addValueEventListener()
, instead of a single-value event listener. A regular value listener will get both the immediate local event and the potential update from the server.
A second solution is to use the new get
method (introduced in early 2021), which doesn't have this problematic behavior. Note that this method always tries to first fetch the value from the server, so it will take longer to completely. If your value never changes, it might still be better to use addListenerForSingleValueEvent
(but you probably wouldn't have ended up on this page in that case).
As a workaround you can also call keepSynced(true)
on the locations where you use a single-value event listener. This ensures that the data is updated whenever it changes, which drastically improves the chance that your single-value event listener will see the current value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With