Data storage is an essential element in Android app development. Cloud Firestore, part of Google’s Firebase platform, is a NoSQL database that enables real-time data storage, synchronization, and management. In this tutorial, we will take a closer look at how to use Cloud Firestore in an Android app using Kotlin.
1. Introduction to Firebase and Firestore
Firebase is a comprehensive platform for mobile and web application development, providing authentication, data storage, hosting, and cloud functions. Firestore is Firebase’s database service, which allows for structured data storage and offers features similar to a real-time database.
1.1 Key Features of Firestore
- Real-time data synchronization
- Scalable
- Unstructured data storage
- Accessible from mobile and web applications
2. Project Setup
After creating a new project in Android Studio, let’s set up Firebase and Firestore.
2.1 Creating a Project in Firebase
- Access the Firebase console and create a new project.
- Add an Android application and enter the package name and SHA-1 key.
- Download the google-services.json file and add it to the app folder of your project.
2.2 Modifying the Gradle File
Add Firebase and Firestore dependencies in the project’s build.gradle
file:
dependencies {
implementation platform('com.google.firebase:firebase-bom:31.0.2')
implementation 'com.google.firebase:firebase-firestore-ktx'
implementation 'com.google.firebase:firebase-auth-ktx'
}
2.3 Initializing Firebase
Initialize Firebase in the application’s entry point, MainActivity
:
import com.google.firebase.FirebaseApp
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
FirebaseApp.initializeApp(this) // Initialize Firebase
}
}
3. Firestore Data Structure
Firestore stores data in the form of documents and collections. A document consists of key-value pairs, and a collection is a group of documents.
3.1 Example of Storing Data
Let’s look at an example of how to store data in Firestore. For instance, if you want to store user information, you can use the following code:
import com.google.firebase.firestore.FirebaseFirestore
class MainActivity : AppCompatActivity() {
private lateinit var db: FirebaseFirestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = FirebaseFirestore.getInstance()
saveUser()
}
private fun saveUser() {
val user = hashMapOf(
"first" to "Jane",
"last" to "Doe",
"born" to 1990
)
db.collection("users")
.add(user)
.addOnSuccessListener { documentReference ->
Log.d(TAG, "DocumentSnapshot added with ID: ${documentReference.id}")
}
.addOnFailureListener { e ->
Log.w(TAG, "Error adding document", e)
}
}
}
4. Reading Data and Real-time Updates
Firestore provides functionality to detect changes in data in real-time. Through this, you can easily receive changes in data and update the UI.
4.1 Example of Reading Data
A basic example of reading data from Firestore is as follows:
private fun getUser() {
db.collection("users")
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
Log.d(TAG, "${document.id} => ${document.data}")
}
}
.addOnFailureListener { exception ->
Log.w(TAG, "Error getting documents: ", exception)
}
}
4.2 Example of Real-time Updates
To detect changes in data in real-time, you can use the addSnapshotListener
method:
private fun listenToUsers() {
db.collection("users")
.addSnapshotListener { snapshots, e ->
if (e != null) {
Log.w(TAG, "Listen failed.", e)
return@addSnapshotListener
}
if (snapshots != null) {
for (doc in snapshots.documentChanges) {
if (doc.type == DocumentChange.Type.ADDED) {
Log.d(TAG, "New city: ${doc.document.data}")
}
// Other types can also be handled (MODIFIED, REMOVED, etc.)
}
}
}
}
5. Modifying and Deleting Data
Modifying and deleting data in Firestore is also very easy. Here’s how to modify and delete data.
5.1 Example of Modifying Data
To modify a specific document, use the following code:
private fun updateUser(userId: String) {
val userUpdates = hashMapOf(
"last" to "Smith", // Change last name
)
db.collection("users").document(userId)
.update(userUpdates)
.addOnSuccessListener {
Log.d(TAG, "User successfully updated!")
}
.addOnFailureListener { e ->
Log.w(TAG, "Error updating document", e)
}
}
5.2 Example of Deleting Data
Here’s how to delete data:
private fun deleteUser(userId: String) {
db.collection("users").document(userId)
.delete()
.addOnSuccessListener {
Log.d(TAG, "User successfully deleted!")
}
.addOnFailureListener { e ->
Log.w(TAG, "Error deleting document", e)
}
}
6. Setting Up Security Rules
One of the most important aspects of using Firestore is security. You can manage data access permissions by setting security rules in the Firebase console.
6.1 Default Security Rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null;
}
}
}
7. Conclusion
In this tutorial, we learned how to use Firebase and Firestore in an Android app using Kotlin. By leveraging Cloud Firestore, you can manage data in real-time and maximize app performance with various features. Try applying this knowledge to real projects to gain more experience.