Home > front end >  Firebase RTDB: Call keepSynced while offline
Firebase RTDB: Call keepSynced while offline

Time:07-01

I'm working on a Flutter app that uses Firebase RTDB. I'm a bit unclear on the mechanism of keepSynced():

Our app creates new collections and adds data to these collections. The app also observes these collections to display the data. In the process, we call keepSynced(true) in order to keep the offline cache alive for these queries. Now we noticed that, when creating a new collection calling keepSynced(true) while offline, the listener we register on the new collection doesn't receive data until the app goes online again. From then on, the caching and updating the listeners works as expected (online offline).

So, in code:

// Execute this while offline:

// Enable permanent offline sync for a new node that doesn't exist yet on the Firebase server
await database.ref().child('new_node').keepSynced(true);

// Register listener
database.ref().child('new_node').onValue.listen((event) => print(event));

// Add data
database.ref().child('new_node/child').set({'key': 'value'});

The listener will trigger only after the device goes online.

The documentation on keepSynced() states

By calling keepSynced(true) on a location, the data for that location will automatically be downloaded and kept in sync, even when no listeners are attached for that location. Additionally, while a location is kept synced, it will not be evicted from the persistent disk cache.

So is it actually required to be connected with the Firebase backend ("will automatically be downloaded") while calling keepSynced() in order for the offline caching/querying to work?

CodePudding user response:

You can call keepSynced at any moment, but the client will only be able to download the data from the server when it is connected to the server.

If that is not the behavior you're observing, please edit your question to include a minimal repro.


Update based on the new repro in your question:

The behavior you're seeing is unfortunate, but expected.

The Firebase API guarantees (undocumented these days) that it will never surface a partial node to your app. Since you're only setting /new_node/child, and it has no knowledge of the current state of /new_node, it doesn't raise a value event on new_node since in only has partial information about that node.

If you were to instead listen for child_added on new_node, the SDK would raise an event in this scenario - but it won't raise a value event since until it can ascertain that it has a complete snapshot of new_node.

The two most common paths forward are:

  • Listen at a lower level in your JSON tree, for example by listening to child_* events (as mentioned above).
  • Perform an initial write operation on all of new_node, so that the local SDK knows what the expected initial state of the node is against it can then perform the lower-level writes. You could possibly then use security rules to reject this priming write operation on the server if there is also data that can't be wiped.
  • Related