Setting up Firebase Realtime Database in Android
Firebase Realtime Database gives an Android app a cloud-hosted JSON store that synchronises data almost instantly. It suits practical projects such as chat screens, shared shopping lists, delivery updates, attendance records and simple multiplayer features.
The database is managed through Firebase, so you do not need to build an API server before saving information. An Android client can write records, listen for changes and receive updated values through Firebase listeners. This makes it approachable for beginners while still supporting production applications.
Australian developers may test with users on different network conditions, from reliable NBN connections in Melbourne or Brisbane to slower or intermittent service in regional Queensland and Western Australia. A well-designed app should show loading states, handle offline data and avoid assuming that every request completes immediately.
This guide uses Android Studio, Gradle and Kotlin. The same Firebase project can support users in Sydney, Adelaide or Perth, while security rules determine exactly which users can read or change each record.
| Part | Purpose |
|---|---|
| Firebase project | Connects the Android app to Google services |
google-services.json |
Identifies the Firebase project in the app |
| Realtime Database | Stores and synchronises JSON data |
| Firebase Authentication | Identifies users before database access |
| Database rules | Protects records from unauthorised reads and writes |
Create the Firebase project
Open the Firebase console and choose Add project. Give the project a clear name, such as CommunityTasks, then continue through the setup screens. Google Analytics is optional for a small tutorial project, so you can disable it if you only want to practise database operations.
From the project overview, select the Android icon to register an application. Enter the package name from your Android module's applicationId, such as com.example.communitytasks. The package name is case-sensitive and must match the value used by Gradle. A nickname and SHA-1 certificate are optional for basic Realtime Database testing, although the SHA-1 becomes useful when adding Google Sign-In or other authenticated services.
Download google-services.json and place it in the app folder, alongside the module's build.gradle or build.gradle.kts file. Do not place it in the project root. Treat this configuration file as part of the app setup, but keep database rules and private server credentials out of public repositories.
Add Firebase dependencies
In a modern Android project, use the Firebase BoM to keep Firebase libraries compatible. With Kotlin DSL, the module-level app/build.gradle.kts can include:
plugins {
id("com.android.application")
id("com.google.gms.google-services")
}
dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.7.0"))
implementation("com.google.firebase:firebase-database")
}
The Google services plugin must also be available to the project-level plugin configuration. Android Studio may offer to sync and resolve the plugin automatically. If your project uses Groovy Gradle files, the dependency syntax changes slightly, but the Firebase BoM approach remains the same.
After editing Gradle files, select Sync Now. A failed sync commonly comes from an incorrect package name, a misplaced JSON file or a plugin version that does not match the Android Gradle Plugin. Resolve these issues before writing Kotlin code, because unresolved dependencies will produce misleading errors in the editor.
Initialise and write data
Realtime Database exposes a database reference that points to a location in the JSON tree. A simple data class can represent a task:
data class Task(
val title: String = "",
val completed: Boolean = false
)
In an activity, fragment or repository, obtain a reference and write a record with a generated key:
private val database = FirebaseDatabase.getInstance()
private val tasksRef = database.getReference("tasks")
fun addTask(title: String) {
val taskKey = tasksRef.push().key ?: return
val task = Task(title = title)
tasksRef.child(taskKey).setValue(task)
.addOnSuccessListener {
// Display a saved message
}
.addOnFailureListener { error ->
// Display error.localizedMessage
}
}
push() creates a unique key that prevents two devices from overwriting the same child. This is useful for a shared list used by people in Sydney and Canberra at the same time. For a known record, use child("fixed-id").setValue(...), but take care that repeated writes replace the existing value.
A small progress indicator and clear error message make a major difference on mobile networks. For visual polish, a status card can use simple interface assets from flat elements while the operation is being saved. Avoid reporting success until the completion listener confirms that Firebase accepted the write.
Read live changes from the database
A ValueEventListener reads the selected location and runs again whenever its contents change:
fun observeTasks(onChanged: (List<Task>) -> Unit) {
tasksRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val tasks = snapshot.children.mapNotNull {
it.getValue(Task::class.java)
}
onChanged(tasks)
}
override fun onCancelled(error: DatabaseError) {
// Log or display the database error
}
})
}
The listener receives a complete snapshot of tasks. Convert that snapshot into a list for a RecyclerView, then submit the list to a ListAdapter. If the screen is destroyed, remove long-lived listeners or attach them through a lifecycle-aware repository pattern to avoid unnecessary work.
For a single read, use addListenerForSingleValueEvent. Queries can limit or order data, for example:
tasksRef.orderByChild("completed")
.equalTo(false)
.addListenerForSingleValueEvent(listener)
Realtime Database can cache data locally and queue writes while a device is offline. That behaviour helps users travelling through regional Australia, but the interface should still indicate when data is pending or stale. Avoid treating locally displayed data as proof that a server-side write has completed.
Secure the database before release
When a Realtime Database is first created, Firebase asks whether to use locked or test mode. Test mode is convenient for an experiment, but it can allow broad public access and should not remain enabled in a released application.
A basic authenticated rule set might look like this:
{
"rules": {
"tasks": {
".read": "auth != null",
"$taskId": {
".write": "auth != null"
}
}
}
}
This permits any signed-in user to read and edit tasks. Real applications usually need ownership checks, validation and separate permissions for administrators. Firebase Authentication should be connected before relying on auth != null; otherwise legitimate users will receive permission errors.
Rules are enforced on Firebase's servers, not just in the Android interface. Validate required fields and restrict data types where possible. Australian organisations should also consider the Australian Privacy Act and their handling of personal information, especially when records contain names, addresses, health details or customer activity.
Test, troubleshoot and maintain the app
Use the Firebase console to inspect the JSON tree while testing. Create a record from the app, confirm its shape, then edit it in the console and watch the Android listener update. This verifies both write and read paths without needing two physical devices.
Common failures include Permission denied, an empty snapshot and null model objects. Permission errors usually indicate database rules or missing authentication. Empty results may come from listening to the wrong path, such as task instead of tasks. Default values in the Kotlin data class help Firebase deserialize incomplete records safely.
Test on an emulator and a real phone, including a device with connectivity disabled. Check dates and times carefully when displaying activity across Australian states, since daylight saving affects New South Wales, Victoria, Tasmania and South Australia differently from Queensland and Western Australia. For tutorial-related enquiries, the site's contact details provide a suitable support route.