Android App Development Course with Kotlin, Cloud Firestore

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

  1. Access the Firebase console and create a new project.
  2. Add an Android application and enter the package name and SHA-1 key.
  3. 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.

References

© 2023 Android Development Blog. All rights reserved.