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?
Why Use It?
Modern, easily maintainable and more importantly, allows you to set up a very scalable database (if your data is stored properly).
Firebase is not only compatible with mobile operating systems (Android and iOS) but is also available for web and native C++ applications. You can find official libraries for AngularJS, ReactJS, and so on…
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.
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.
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.
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.
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 (which are 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.
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 load.
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 as Parse (R.I.P) used to provide.
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.
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.
First things first, the project is divided into four modules:
- mobile: contains all the code specific to the mobile application only
- wear: code specific to the wearable devices (Android Wear 2.0)
- Shared: this module hosts the code shared by the two module above
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.
- Authentication using e-mail and password
- Creating new tasks with priorities and tags
- Swipe to mark a task as done
- User logout
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.
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 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:
Be mindful with the event listeners:
- The closer the target node is to the root node, to more data snapshots you’ll receive.
- Do not forget to remove the listeners when you no longer need them.
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.
One of its numerous advantages is that it makes unit testing (more on that later) of asynchronous work easier. That’s why I decided to wrap the Firebase events using RxJava Observable/Single (depending the scenario):
Above is an example using Single. A Single works almost exactly the same way as an Observable, except that only one result is expected.
Using tools such as RxJava, Otto, EventBus requires you to be cautious with memory leaks.
For instance with RxJava, 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:
I chose to use RxLifecycle, which is a library created by the Trello team. Let’s have a look at how to use it simply with the Sign-In scenario:
- We create BaseRxActivity:
2. We make sure the Observer is unsubscribed on Activity#onDestroy() — obviously, you can select the activity event that you want, and it works with fragments as well.
That way, you don’t have to worry about anything.
Plain Java Ordinary 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.
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 Jackson tools to serialise/unserialise, there are few rules that you need to be aware of :
- Every stored class must contain an explicit empty constructor.
- Every stored variable in these classes must have a public getter.
- Use @Exclude to annotate the methods and fields that you don’t want to serialise.
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.
I really enjoyed working on Firebase, everything is easy and works seamlessly. However, I have some noteworthy concerns about it.
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.
Going for a client-centric option such as Firebase can be a problem if you need third party service access from your backend.
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.
At the moment, the FireBucket app is pretty basic. Upcoming features could include:
- Google Sign-In
- Search among tasks
- Dynamic Links
That’s it for now — I’m planning to focus on the Wear 2.0 version of the app and some other projects.