You're viewing the legacy docs. They are deprecated as of May 18, 2016.

Java Android Guide

Offline Capabilities

Firebase apps work great offline and we have several features to make the experience even better. Enabling disk persistence allows your app to keep all of its state even after an app restart. We provide several tools for monitoring presence and connectivity state.

Disk Persistence

Firebase apps automatically handle temporary network interruptions for you. Cached data will still be available while offline and your writes will be resent when network connectivity is recovered. Enabling disk persistence allows our app to also keep all of its state even after an app restart. We can enable disk persistence with just one line of code.

Firebase.getDefaultConfig().setPersistenceEnabled(true);

With disk persistence enabled, our synced data and writes will be persisted to disk across app restarts and our app should work seamlessly in offline situations.

Persistence Behavior

By enabling persistence, any data that we sync while online will be persisted to disk and available offline, even when we restart the app. This means our app will work as it would online using the local data stored in the cache. Listener callbacks will continue to fire for local updates.

The Firebase client automatically keeps a queue of all write operations that are performed while our application is offline. When persistence is enabled, this queue will also be persisted to disk so all of our writes will be available when we restart the app. When the app regains connectivity, all of the operations will be sent to the server.

If our app uses Firebase Authentication, the client will persist the user's authentication token across restarts. If the auth token expires while our app is offline, the client will pause our write operations until we re-authenticate, else our writes might fail due to security rules.

Keeping Data Fresh

Firebase synchronizes and stores a local copy of the data for active listeners. In addition, you can keep specific locations in sync.

The client will automatically download the data at these locations and keep it in sync even if the reference has no active listeners. You can turn synchronization back off with the following line of code.

scoresRef.keepSynced(false);

By default, 10MB of previously synced data will be cached. This should be enough for most applications. If the cache outgrows its configured size, Firebase will purge data that has been used least recently. Data that is kept in sync, will not be purged from the cache.

Querying Data Offline

Firebase stores data returned from a query for use when offline. For queries constructed while offline, Firebase continues to work for previously loaded data. If the requested data hasn't loaded, Firebase loads data from the local cache. When we come back online our data will load and reflect the query.

Now let's assume that the user loses connection, goes offline, and restarts the app. While still offline, we query for the last two items from the same location. This query will successfully return the last two items because we had loaded all four in the query above.

In the above example, the firebase client raises 'child added' events for the highest scoring two dinosaurs, via our persisted cache. But it will not raise a 'value' event, since we've never done that query while online.

If we were to request the last six items while offline, we'd get 'child added' events for the four cached items straight away. When we come back online, the Firebase client will synchronize with the server and we'll get the final two 'child added' and the 'value' events.

Handling Transactions Offline

Any transactions that are performed while our app is offline, will be queued. Once the app regains network connectivity, the transactions will be sent to the server.

Transactions are not persisted across app restarts

Even with persistence enabled, transactions are not persisted across app restarts. So you cannot rely on transactions done offline being committed to your Firebase database. To provide the best user experience, your app should show that a transaction has not been saved into your Firebase database yet, or make sure your app remembers them manually and executes them again after an app restart.

Firebase has many features for dealing with offline scenarios and network connectivity. The rest of this guide applies to your app whether or not you have persistence enabled.

Managing Presence

In realtime applications it is often useful to detect when clients connect and disconnect. For example, we may
want to mark a user as 'offline' when their client disconnects.

Firebase clients provide simple primitives that allow data to be written to the database when a client disconnects from the Firebase
servers. These updates will occur whether the client disconnects cleanly or not, so we can rely on them to clean
up data even if a connection is dropped or a client crashes. All write operations, including setting,
updating, and removing, can be performed upon a disconnection.

Here is a simple example of writing data upon disconnection by using the onDisconnect primitive:

How onDisconnect Works

When an onDisconnect() operation is established, it lives on the Firebase server. The server checks security to
make sure the user can perform the write event requested, and informs the client if it is invalid. The server then
monitors the connection. If at any point it times out, or is actively closed by the client, the
server checks security a second time (to make sure the operation is still valid) and then invokes the event.

The client can use the callback on the write operation to ensure the onDisconnect was correctly attached:

OnDisconnect onDisconnectRef = presenceRef.onDisconnect();
onDisconnectRef.setValue("I disconnected");
// some time later when we change our minds
onDisconnectRef.cancel();

Detecting Connection State

For many presence-related features, it is useful for a client to know when it is online or offline. Firebase
clients provide a special location at /.info/connected which is updated every time the client's connection
state changes. Here is an example:

/.info/connected is a boolean values which is not synchronized between clients because the values are
dependent on the state of the client. In other words, if one client reads /.info/connected as false, this is no
guarantee that a separate client will also read false.

Handling Latency

Server Timestamps

Firebase servers provide a mechanism to insert timestamps generated on the server as data. This feature, combined with
onDisconnect, provides an easy way to reliably make note of the time at which a client disconnected:

Clock Skew

While Firebase.ServerValue.TIMESTAMP is much more accurate, and preferable for most read/write ops,
it can occasionally be useful to estimate the clients clock skew with respect to Firebase's servers. We
can attach a callback to the location /.info/serverTimeOffset to obtain the value, in milliseconds,
that Firebase clients will add to the local reported time (epoch time in milliseconds) to estimate the server time. Note
that this offset's accuracy can be affected by networking latency, and so is useful primarily for discovering
large (> 1 second) discrepancies in clock time.

Sample Presence App

By combining disconnect operations with connection state monitoring and server timestamps, we can build a user
presence system. In this system, each user stores data at a database location to indicate whether or not a client is
online. Clients set this location to true when they come online and a timestamp when they disconnect. This timestamp
indicates the last time the given user was online.

Note that the disconnect operations should be queued before a user is marked online, to avoid any race conditions
in case the client's network connection is lost before both commands can be sent to the server.

Here is a simple user presence system:

// since I can connect from multiple devices, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
final Firebase myConnectionsRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/users/joe/connections");
// stores the timestamp of my last disconnect (the last time I was seen online)
final Firebase lastOnlineRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/users/joe/lastOnline");
final Firebase connectedRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/.info/connected");
connectedRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
// add this device to my connections list
// this value could contain info about the device or a timestamp too
Firebase con = myConnectionsRef.push();
con.setValue(Boolean.TRUE);
// when this device disconnects, remove it
con.onDisconnect().removeValue();
// when I disconnect, update the last time I was seen online
lastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP);
}
}
@Override
public void onCancelled(FirebaseError error) {
System.err.println("Listener was cancelled at .info/connected");
}
});