back to posts

Firebase database and Android Sync

I want to share my experience with Firebase Realtime Database and it's integration with Android using the "offline" mode it provides. I won’t get into a lot of technical details but instead I will give a few highlights of how it was for me.
Spoiler alert... it was great!

Before starting, a brief background: on the database side my experience is based more on relational databases, and on the Android side I mostly worked by developing the Sync service myself by interacting with an API (which sometimes I also needed to maintain). That is probably your background too, so hopefully you’ll find this article helpful.

The Database

When I first got in touch with Firebase Realtime Database, I had these reactions:

  • NoSQL database?.. Mmm... interesting. It didn’t seem that different, until it did.
  • RESTful API out of the box? Based on my dynamic structure? Cool.
  • “Offline Capabilities”? That sounds like something I would be really interested in.

So, let’s move step by step. Firebase Realtime Database is a NoSQL database. That fact forced me to think my data structure in a different way from what I was used to, obviously. I found myself being more flexible on the structure, and even repeating data, and that was totally fine. I won’t spend much time talking about how a NoSQL database works (that’s perhaps for another article), but the best way of approaching it is thinking that all our data will be stored in a big JSON file. For example:

{
    "users": {
        "james_howlett": {
            "name": "James Howlett",
            "groups": { "hunters": true, "mutants": true },
            "space_experience": true
        },
        "sam_winchester": {
            "name": "Sam Winchester",
            "groups": { "hunters": true },
        },
        "william_adama": {
            "name": "William Adama",
            "space_experience": true
        },
        "stewie_griffin": { ... }
    },
    "groups": {
        "hunters": { "name": "Hunters" },
        "mutants": { "name": "Mutants" }
    }
}

Firebase gives us nice and simple web management tool where we can Create/Read/Update/Delete items in your database (that big JSON file) with a few clicks. It also provides, and this is one of the best parts, a ready-to-use RESTful API that allows us operate on that database no matter the structure we have.

For example, with this call:

GET https://....firebaseio.com/users/william_adama

We can get all the information about Admiral William Adama.

We can also define different set of rules for the different data trees, like access permissions or integrity conditions. And, of course, authorization is a very present piece of the architecture that it’s also taken care of.

The Android

The Firebase Realtime Database can be used from different platforms, like Web or iOS, and all cases are similar: you integrate the proper Firebase Library and start playing around. For Android, you will need to include the corresponding library for Firebase Database into your project, setup keys and configuration, and start using it.

The first thing I noticed was that querying the database was different from previous experiences I had, for the following reasons:

  • I wasn’t able to do “joins” in the relational sense of the concept, mostly because of the NoSQL nature of the database. So I needed to pull each piece of data at a time by filtering properly.
  • Data was returned asynchronously, which meant changes in the app logic to make everything work and not crash.

Here is how a simple pull for data would look like:

dbReference.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot snapshot) {
        //the data, at the “dbReference”, has changed
        //in other words, here you will get the data you were looking for
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {
        //the data retrieval was cancelled
    }
});

The “dbReference” variable holds a reference to a specific path of your data (e.g., “{root_path}/groups/hunters”). And, as you can see, you will get the value on that reference asynchronously when the “onChange” method of the listener gets called.

The same goes for setting/saving values:

dbReference.setValue(newValue, new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
        //Called when the value was set
        //Here you can notify the user or continue with other processes
    }
});

Once I got used to that way of doing things, I had no trouble in scaling the app and the database without major obstacles.

The Sync and the Offline mode

One nice feature Firebase Realtime Database offers, is the possibility to enable the “Offline mode” (or Disk Persistence), which allows the app to work on the database while offline (local copy) and then sync everything back with the Database server when it’s online again.

Everything can be enabled with one simple line of code:

FirebaseDatabase.getInstance().setPersistenceEnabled(true);

Quick disclaimer: that line can only be called once for the database, and before doing any operation with it. My recommendation is that you implement a Factory and/or Singleton pattern to achieve that.

Having this possibility allowed my app to have a sync feature out of the box, without having to develop my own Sync Adapter and without having to change it after each database structure changes.

One caveat of this great feature is that, once the Offline mode was enabled, I didn’t have much control over the sync process itself. I couldn’t know or alter the time of sync, or decide if I wanted to take the data directly from the source (online), or even if I wanted to refresh the local copy. I had some problems when I updated some data in the Firebase online database and those changes weren’t reflected on the client App, even if it was online.
There are supposedly some methods or calls you can make to achieve that, but they are not 100% effective or work as expected, so keep that in mind.

One final comment is that, at the time of writing this article, there is no way of clearing the local database of the device. So if you face some issues with local data being out-of-date, you’ll need to do some manual work to prevent crashes or solver your problems.

Conclusion

I already spoiled the conclusion at the beginning, but I’ll say it again: it was (still is) a great resource. Using the Firebase Realtime Database solved many common issues by providing a API accessible online database with offline sync out of the box. Many development hours were saved in the process and that is something to be grateful for.

There are still several features to add or polish, and the community is taking care of requesting them. In the meantime, I recommend you to give it a try.

 Useful links & sources

Improve your business, contact us!

Let's talk