12.
Introduction to Firebase Realtime Database
Written by Dean Djermanović
Having a central place for storing application data is a common requirement for mobile applications. Let’s say you’re building a mobile game and you need to save user progress. You can save it locally on the phone. But what if the user logs in with the same account on a different device? That device doesn’t know that the user has already made some progress and the user will need to start the game all over again. That can lead to unhappy users and bad app reviews.
In this case, you would need to save user progress to a remote database so that users can have access to the data from any number of devices they own. That database is usually hosted somewhere, on the Internet, making it accessible through a simple network connection. This concept is known as the cloud. You can think of the cloud as someone else’s computer, or an entire infrastructure, which you’ve rented for various services.
Firebase Realtime Database is a solution that stores data in the cloud and provides an easy way to sync your data among various devices. It is powered by the Google Firebase platform, and is just a single piece in an otherwise large puzzle. In this chapter, you’ll learn how the Realtime Database works and its key capabilities. Furthermore, you’ll add the Realtime Database to an Android project. Along the way you’ll learn how the Realtime Database takes care of security with database rules, how data is saved to the database and the best practices for data structure.
Overview
Firebase Realtime Database is a cloud-hosted database that supports iOS, Android, Web, C++ and Unity platforms.
Realtime means that any changes in data are reflected immediately across all platforms and devices within milliseconds. Most traditional databases make you work with a request/response model, but the Realtime Database uses data synchronization and subcriber mechanisms instead of typical HTTP requests, which allows you to build more flexible real-time apps, easily, with less effort and without the need to worry about networking code.
Many apps become unresponsive when you lose the network connection. Realtime Database provides great offline support because it keeps an internal cache of all the data you’ve queried. When there’s no Internet connection, the app uses the data from the cache, allowing apps to remain responsive. When the device connects to the Internet, the Realtime Database synchronizes the local data changes with the remote updates that occurred while the client was offline, resolving any conflicts automatically.
Client devices access the Realtime Database directly, without the need for an application server. Security rules take care of who has access to what data, and how they can access it. You’ll learn more about security rules later in this chapter.
Firebase Realtime Database is not completely free. There are certain pricing plans. If you want your app to scale you’ll need to pay for the number of connections, disk usage and network usage. You can check out pricing plans on the firebase pricing plans page here: https://firebase.google.com/pricing/.
Realtime Database is a NoSQL database. NoSQL stands for “Not only SQL”. The easiest way to think of NoSQL is that it’s a database that does not adhere to the traditional relational database management system (RDMS) structure. As such, the Realtime Database has different optimizations and functionality compared to a relational database. It stores the data in the JSON format. The entire database is a big JSON tree with multiple nodes. When planning your database you need to keep this in mind to make your database as optimized as possible. You’ll also learn more about data structure and best practices later in this chapter.
Setting up Realtime Database
In Chapter 11, “Firebase Overview,” you added your app to a Firebase project. Now, you need to connect your app to Firebase, to enable its services.
Prerequisites
There are few requirements that you need to fulfill in order to setup Firebase with Android.
- To run your app on a physical device or an emulator you need to have at least API level 9, which is Android 2.3 Gingerbread.
- The device must have Play Services 9.0 or later. You can check your Play Services version in the settings of the device.
- Your app needs to use Gradle 4.1 or higher.
- Your app needs to target API level 16 or later.
Connecting the app to the project
Go to the Firebase console and open WhatsUp project that you created.
Click on the Android icon to connect your Android app with Firebase. You should see the following :
Registering app
The first step is to register your app. For that, you need two pieces of information. The first one is your app’s package name which you can find in the app-level build.gradle file as applicationId. Enter com.raywenderlich.whatsup as the package name.
App nickname is optional so you won’t add it.
The second thing that you need to provide is the SHA1 hash of your debug key. This is only required if you’ll use specific Firebase features. In this project, it’s needed for the Authentication feature. You can get your SHA1 hash in two ways, by using Android Studio, and Gradle, or by typing in a terminal command.
For the first option, open up the Gradle tab from the right-hand side toolbar, and locate the following task:
Run it, and you should see the output in the terminal. The alternative is running the following command:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
In the Android Studio’s Terminal panel, for your project.
Both of the options command some information about your debug keystore. You’ll see there a line that starts with SHA1.
Alias name: androiddebugkey
Creation date: Oct 26, 2018
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: C=US, O=Android, CN=Android Debug
Issuer: C=US, O=Android, CN=Android Debug
Serial number: 1
Valid from: Fri Oct 26 13:29:17 CEST 2018 until: Sun Oct 18 13:29:17 CEST 2048
Certificate finger s:
SHA1: A6:72:CD:92:A6:DD:84:31:FA:73:83:48:F6:9D:D4:54:C1:94:07:05
SHA256: E0:67:78:A8:38:18:41:35:3B:24:C3:87:01:73:29:BC:A8:55:71:E0:08:00:76:CF:4D:C0:93:38:47:93:FD:54
Signature algorithm name: SHA1withRSA
Subject Public Key Algorithm: 1024-bit RSA key
Version: 1
Copy the value after that. That value is just a series of hex values, which represent your application’s debug keystore signature. Paste that value into the Debug signing certificate SHA-1 text box in the console. Click Register app button.
Downloading config file
Next, you need to download the google-services.json config file by clicking the blue button, and add it to your Android project. Follow the instructions in the console to do that, so that you paste it to the correct location. This file contains your app configuration. If your Firebase configuration changes later you’ll need to download an updated config file and replace the existing one.
Adding Firebase SDK
Next, you need to add the Firebase client libraries to your app. Follow the instructions in the console for this, as well.
First, you need to add the Google Services Gradle plugin to your build script configuration. This plugin reads google-services.json config file and injects some of its values into your build. Here, you’ll also add a dependency to Firebase core. Make sure to use the latest version. You can check the documentation — found here https://firebase.google.com/docs/android/setup#available-libraries — to find the latest version. Once you do that click Next button.
Verifying installation
The last step is to verify if everything is set up correctly. For this, you only need to run your app on a device or an emulator. Before you do that, go to the LoginActivity class and uncomment the code. Repeat the process for the HomeActivity and AuthenticationManager classes. Run your app. If everything is set up correctly you’ll get verification message in the console.
You can click the Continue to console button now.
Adding Realtime Database
First, you need to create your database in the console. From the menu on the left select Database. Scroll to the Realtime Database section and click the Create database button. The security rules dialog will open:
Select the second option, Start in test mode, and click the Enable button. You’ll learn more about security rules in a bit.
Once your database is created you’ll get this:
To add the Realtime Database service to your app, you only need to add one more dependency. Open up build.gradle file, if you haven’t got it open and add the following dependency, making sure you’re using the latest version:
implementation 'com.google.firebase:firebase-database:16.1.0'
Database rules
In this section, you’ll be working on WhatsUp app which has an authentication feature so the app can know who your users are. Authentication is the process of verifying users are who they say they are, and to give them certain security access to your service.
User identity is an important security concept. Different users have different data and different capabilities. In this app, the user will be able to delete posts it created but not the other people’s posts. Because of this, you need a way to control who has access to what data in your database. The process of determining who has access to what is called authorization.
To implement the various aspects of security, authentication and authorization would require a lot of work. Firebase has the Authentication service which can use for all those sides of security, and the Realtime Database service uses internal Realtime Database Rules for authorization. Database rules allow you to control access for each user. They determine who has read and write access to your database, how your data is structured, and what indexes exist. Every time reading or writing is attempted, a request will only be completed if your rules allow it.
Firebase Database rules are also a JSON object which must have a top-level rules node. By default, the rules node contains two primitives, .read and .write and they determine who has read and write access. If .read and .write are set to true, everyone would have complete access to your data, so they can both read and write as they want. To protect your database from the abuse, you need to customize those rules.
The Firebase Database Rules include built-in variables and functions that allow you to refer to other paths, server-side timestamps, authentication information, and much more. For this app, you’ll write a rule that grants read and write access only for authenticated users.
This is what this rule looks like:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Navigate to the Rules tab, replace the rules with the above snippet and click Publish:
Now, only authenticated users are allowed to read from and write to your database.
You can learn more about database rules in the documentation here: https://firebase.google.com/docs/database/security/.
Communication with the Realtime Database
You need a way to talk to the Realtime Database. The first thing you need is a connection. To get a connection you need to create a database reference first. Open RealtimeDatabaseManager class and add the databaseReference property:
private val databaseReference = FirebaseDatabase.getInstance().reference
This gets you a reference to the root of the Firebase JSON tree. You’ll learn more about data structure later in this chapter.
For connectivity testing purposes, add a method to the RealtimeDatabaseManager that will write some dummy data to the database.
fun addDummyData() {
databaseReference.setValue("Saving data on Android")
}
Next, open HomeActivity class and add the realtimeDatabaseManager property:
private val realtimeDatabaseManager by lazy { RealtimeDatabaseManager() }
Call realtimeDatabaseManager.addDummyData() from the initialize() method.
Run the app and sign in with your Google account by clicking the Sign in with Google button. Next, go to the Firebase console and select Database from the menu on the left side. You should see your data in the database.
Congratulations! You have successfully communicated with the Realtime Database. Before you continue, delete the data from the database directly from the console by clicking the X button from the right side of the value. You’ll learn a lot more about reading and writing to the Realtime Database in the next chapter.
Data structure
JSON format
As mentioned before, the Firebase Realtime Database stores data in the JSON format. JSON stands for JavaScript Object Notation and it’s a language-independent data format with a minimal number of value types: strings, numbers, booleans, lists, objects, and null. It consists of key/value pairs. The key/value pairs are separated by a colon and each pair is separated by a comma. It is easy for humans to read and write and for machines to parse and generate. This is a sample JSON object:
{
"name": "Dean",
"lastname": "Djermanovic",
"age": 23,
"gender": "male"
}
Best practices for data structure
The entire database is a big JSON tree with multiple nodes. When pushing new data to the database you either create a new node with an associated key or update an existing one. Therefore there is the danger of creating a deeply nested structure. Firebase Realtime Database allows nesting data up to 32 levels deep but that doesn’t mean that this should be the default structure. When thinking about data structure you need to think about how your data is going to be consumed, you need to make the process of saving and retrieving as easy as possible.
If you have very complex structures with a lot of nesting you fetch all the data every time you read from the database, which is not needed in most of the cases. If you want to get the data from a specific node you get all the data below that node as well. Take a look at this restaurants structure for example:
{
"restaurants": {
"first_restaurant": {},
"second_restaurant": {},
"third_restaurant": {}
}
}
Fetching the restaurant’s data would get you all of its child nodes data as well. In addition, when you grant someone access at a node in your database you also grant them access to all of its children’s data. You can limit this by specifying how many restaurants you want to fetch or to fetch only restaurants that satisfy some condition but in general, when you’re loading data you’re loading all of it. Because of this, it’s good practice to keep your data structure as flat as possible.
Another good practice would be that you organize your data in a way that you don’t fetch the data that you’re not rendering on the UI. If you split your data into separate paths you can be more specific about what data you want to fetch. Traditionally, you would have a set of data and you’d build your UI on top of that, but with Firebase, since it’s easy to write data, people build their UI and then they start building a data structure from the app. This flat data structure affects the performance in a good way since you don’t need to fetch extra data that you won’t use, which allows the UI to stay responsive and fast.
Generally, there’s no right or wrong approach to structuring your data. Storage is cheap. You can have a million copies of the exact same string field in the Realtime Database and it will cost you almost nothing but the problem appears when fetching this data. With a little bit of practice, you’ll be able to judge better what makes sense to nest and what doesn’t.
Key points
- To use Firebase Realtime Database in your Android project you need to go through the configuration process first.
- The Realtime Database provides database rules to control access for each user.
- Firebase Authentication is very much connected to database solutions Firebase offers, since it controls the access to data, on a per-user-basis.
- Firebase Realtime Database stores data in JSON format.
- Because the structure is a JSON, it operates with simple data like numbers, strings, objects, booleans and lists.
- Firebase Realtime Database data structure should be as flat as possible and designed with scaling in mind.
Where to go from here?
In this chapter, you saw how to configure Realtime Database and what are best practices when it comes to structuring your data. If you want to learn more you can check out official Firebase documentation.
You also wrote your first data to the database. In Chapter 13: Reading to and writing from Realtime Database you’ll learn a lot more about reading from and writing to Realtime Database and you’ll integrate it to the WhatsUp app. You’ll be able to write posts from the app and upload it to the Realtime Database and other users will be able to read it.