A Glimpse of Firebase, with Firebucket

We’ve all heard a lot about Firebase lately. So I wanted to give it a try myself, by writing a bucket list app — Firebucket (I know, very original).

What Is Firebase?

Firebase is a BaaS (Backend As A Service) — aside from the original realtime cloud-hosted NoSQL database, plenty of services have been added, most of them announced during the Google I/O 2016.

Why Using It?

Modern, easily maintainable and more importantly, allows you to set up a very scalable database (if your data are stored properly).

Cross-platform

Firebase is not only compatible with mobile operating systems (Android and iOS). Its also available for web and native C++ applications. You can find official libraries for AngularJS, ReactJS, and so on…

Modern Database

Forget about the obsolete and exhausting relational way of storing data. Firebase is a key-value pair database. I know, it’s already how Realm works, but trust me, Firebase is even easier and more fun to play with.

You can even look at the content of the database directly from the dashboard.

A glance of the database content through the dashboard

Offline mode

Another awesome capability offered by Firebase is the offline mode. Basically, a copy of the database will be saved and maintained on your local storage. Yep, that’s right, you won’t need to write a ton of boilerplate code to cache things depending on your network connectivity state.

The local and remote databases synchronise once your device is connected.

Presence

Nowadays, showing the user online status is something very common. Facebook does it, as do Slack, WhatsApp, Skype and so on… you get the picture.

Thankfully, to make our lives easier, the Firebase team cooked FirebaseDatabase#onDisconnect() allowing us to easily handle this scenario.

Ok, let’s take a look at what Firebase has to offer.


Firebase Overview

Authentication

Nothing very new here, but Firebase allows you to manage users. The interesting part is the anonymous authentication.

Creating anonymous accounts makes it much easier to use different security rules for users who are not signed in. These accounts can be linked to their credentials further down the road when users log in. That way, they don’t lose data during their user journey.

Even better, Firebase allows us to easily implement sign-ins from different services such as Google, Facebook or Twitter.

List of third-party services Sign-In possibilities

Analytics Tracking

Google Analytics, MixPanel, Flurry — there’s a plethora of great analytics tools available on the market. The real strength of Firebase Analytics is that you can use BigQuery to perform very complex breakdowns of your gathered data.

Under the hood, Firebase analytics use the Activity#ActivityLifecycleCallbacks (universal activity callbacks) by listening to every event (onStart, onResume, onPause, onStop, …).

The classic parameters such as location, device information or even user engagement are also tracked.

Crash Report

Firebase Crash Report allows you to capture manual events as well as app crashes.

“Smart” is the word to describe the crash report dashboard. The way the data are grouped by clusters and displayed will make tracking less time consuming.

NB: the crash reports takes approximately 15 minutes to be visible on the dashboard.

Firebase Cloud Messaging

Basically, Google Cloud Messaging becomes Firebase Cloud Messaging. No reason to worry— the protocol has not changed and GCM will continue to work seamlessly.

The only new feature here is Firebase Notifications, which allows you to send custom notifications directly from your dashboard to specific audiences, the same feature that Parse (R.I.P) used to provide.

Remote Config

To me, this is the coolest feature of Firebase.

Particularly handy for A/B testing (but not only), Remote Config allows you to change some values of your app directly from your Firebase dashboard. You won’t even need to submit an app update on the Play Store, the changes will take place seamlessly.

Even better, you can apply these changes to a specific audience only.

Here are some use cases:

  • Changing the colour of a button
  • Notifying your entire user base about the latest version of your app
  • Displaying a specific message/alert

I won’t go deeper into how to implement Remote Config as the documentation is really well written.

I recommend that you read this section of the documentation, and this one — they touch upon conditional values, audiences, and so on.


For the sake of the project, I wanted to go all-in with Firebase, using as many features as I could even if I didn’t use all the features specified above.


Structure

Clean Architecture

First things first, the project is following a Clean Architecture approach in order to ensure a good code abstraction, by separating the different layers of the app:

  • Presentation: mainly UI related code (activities, fragments, presenters, …)
  • Domain: business logic (models, use cases)
  • Data: API related (entities, data sources, repositories)

Patterns

For this project, I chose to mix two different patterns — MVP (Model-View-Presenter) for most of the app and MVVM (Model-View-ViewModel) when in my opinion it makes the more sense (coupled with RecyclerViews using Android Data Binding).

Data Binding is awesome, but you have to know when to use it and where it’s unnecessary. For instance, while it makes sense with RecyclerViews, I’d rather use a view injection tool such as ButterKnife for the traditional Activities and Fragments.

Features

  • Authentication using e-mail and password
  • Creating new tasks with priorities and tags
  • Swipe to mark a task as done

Writing Data

addOnCompleteListener, addOnSuccessListener and addOnFailureListener. They all take a listener as a parameter. But they also have a variant — you can specify a reference to a particular activity so the callbacks are scoped to a given activity only and will not be triggered if the activity went through Activity#onStop().

Make sure you are providing a specific activity as it’s really important to avoid memory leaks.

Retrieving Data

Fetching data with Firebase is where “realtime database” takes on its full meaning.

In simple words, you can add event listeners on each node and be instantly notified in-app of the changes (data updated/added/removed).

Let’s take an example directly from Firebucket.

The user is on the main view (the bucket list) and we want him to know if a task has been added, updated or removed. All we have to do is to add a listener on the node below:

/users-tasks/{user_uuid}/tasks
NB: the code has been modified to be easily readable.

Be mindful with the event listeners:

  1. The closer the target node is to the root node, to more data and events you’ll receive.
  2. Do not forget to remove the listeners when you no longer need them.

Rx*

RxJava & RxAndroid

When it comes down to handling events and asynchronous tasks, you won’t find a combination that’s more complete than the combo RxAndroid-RxJava.

Therefore, they could be the subject of an entire article. I recommend this series from Dan Lew if you want to know more about how it works as well as the best practices.

My point is that RxJava is incredibly useful and is starting to get lots of attention from Android developers, including myself.

That’s why I decided to wrap the Firebase events using RxJava Observable/Single (depending on the scenario):

Above is an example using a DisposableObserver. It works the same way as an Observer, except that it implements the Disposable interface and thus can be cancelled at any time (asynchronously).

Memory Leaks

Using tools such as RxJava, Otto, EventBus requires you to be cautious with memory leaks.

For instance with RxJava, in most cases, you have to make sure your Observers are no longer able to receive any data once your user leaves the view.

To do so, you have several options:

  1. Disposing them manually
  2. Using CompositeDisposable
  3. Using RxLifecycle

CompositeDisposable

I chose to use CompositeDisposable as below:

  1. As you can see below, we create BaseUseCase from which all the use cases will inherit from:
Complete code here.

2. We then make sure the Observer is disposed on LoginPresenter#detachView() .

Complete code here.

That way, you don’t have to worry about anything.

Model Storage

POJO

Plain Java Old Object is the meaning behind this strange acronym. What does it mean?

It means you’ll be able to store your models by using simple Java classes.

JSON

In order to store your objects, Firebase needs to serialise them first, and of course unserialise them when you retrieve your data.

What’s better than the JSON format to do so? As Firebase is using GSON tools to serialise/unserialise, there are few rules that you need to be aware of :

  1. Every stored class must contain an explicit empty constructor.
  2. Every stored variable in these classes must have a public getter.
  3. Use @Exclude to annotate the methods and fields that you don’t want to serialise.
  4. Use @Keep for your entities to avoid Proguard to mess with them.

Task Reminder

With API 21 (Lollipop), Google introduced JobScheduler. Long story short, it is an optimised and smarter version of the AlarmManager.
The flip side is that it is only available for API 21+.

Luckily the Firebase team is providing an alternative based on JobScheduler but backward compatible with API 9 and above called Firebase JobDispatcher.

Therefore, I decided to use this module to set a task reminder:

Compete code here.

Parallel Task Execution

Sometimes you just want to do many things at once.

Let’s take the example of user Sign-In:

We have information about them on both Auth API (credentials) and in the database (user profile information).

Scenario 1 (Serial Tasks)

Scenario 2 (Parallel Tasks)

If one of these tasks fail, finalTask will fail, therefore, it is fair to say that you can consider this task as a transaction.

Parallelisation as above can be tricky to perform correctly on Java/Android. It doesn’t get much easier than what Firebase has to offer in that regard.

It is very similar to Observable#combineLatest() (from RxJava) when you have to execute multiple REST calls asynchronously.

Conclusion

I really enjoyed working on Firebase, everything is easy and works seamlessly. However, I have some noteworthy concerns about it.

Push Notifications

The first one is the lack of module allowing to send push notifications without any HTTP/XMPP server. However, I have no doubts that they will work on that sooner or later.

Google Play Services

The fact that Firebase is dependent on Google Play Services is no small problem — what about non-Google devices, e.g. Amazon devices? Therefore, you’re automatically losing part of the Android market.

Backend Needs

Going for a client-centric option such as Firebase can be a problem if you need third party service access from your backend.

Think Twice

If you start a small to medium project from scratch, Firebase is a really interesting choice with a lot of possibilities and a relatively small amount of time needed to crack on.

On the other hand, for an existing project, It may be a big hassle to migrate.

UPDATE

At the time of writing, Firebase didn’t have the Cloud Functions. It is a game changer as the feature now allows to send FCM notifications without any third party service.


What’s Next

At the moment, the FireBucket app is pretty basic. Upcoming features could include:

  • Google Sign-In
  • Search for tasks
  • Reminders
  • Dynamic Links

Full source code available on GitHub.

Download the app on the Google Play Store.