Chapters

Hide chapters

Saving Data on Android

Second Edition · Android 11 · Kotlin 1.5 · Android Studio 4.2

Using Firebase

Section 3: 11 chapters
Show chapters Hide chapters

19. Reading Data from Cloud Firestore
Written by Harun Wangereka

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

In the previous chapter, you learned how to write data to Firestore, and how to update or delete data from Firestore by implementing that functionality in the WhatsUp app. You also became familiar with the Firebase console and learned how to use it for managing data.

In this chapter, you’ll continue working on your app. Since now you still don’t have any data on the home screen when you run the app, you’ll focus on implementing reading logic. In the process, you’ll learn how to read data from Firestore, how to listen for updates in real-time, and how queries work.

Setting up Firebase

If you skipped previous chapters, you need to set up Firebase to follow along. Do the following steps:

  1. Create a project in the Firebase console.
  2. Enable Google sign-in.
  3. Set security rules to the test mode to allow everyone read and write access.
  4. Add google-service.json to both starter and final projects.

To see how to do this, go back to Chapter 12: “Firebase Overview” and Chapter 13: “Introduction to Firebase Realtime Database.”

Be sure to use the starter project from this chapter, by opening the reading-data-from-cloud-firestore folder and its starter project from the projects folder, rather than continuing with the final project you previously worked on. It has a few things added to it, including placeholders for the code to add in this chapter.

Reading Data

Like the Realtime Database, Firestore allows to read data once or to listen for data changes in real-time.

database.collection("posts")
    .get()
    .addOnSuccessListener { result ->
      ...
    }
    .addOnFailureListener { exception ->
      ...
    }

Listening for Data Changes

If you don’t have the project open by now, make sure to open it, and head over to CloudFirestoreManager.kt. Add a postsRegistration this field below commentsValues variable:

private lateinit var postsRegistration: ListenerRegistration
// 1
postsRegistration = database.collection(POSTS_COLLECTION)
    // 2
    .addSnapshotListener(EventListener { value, error ->
        // 3
        if (error != null || value == null) {
            return@EventListener
        }
        // 4
        if (value.isEmpty) {
            // 5
            postsValues.postValue(emptyList())
        } else {
            // 6
            val posts = ArrayList<Post>()
            // 7
            for (doc in value) {
                // 8
                val post = doc.toObject(Post::class.java)
                posts.add(post)
            }
            // 9
            postsValues.postValue(posts)
        }
    })
import com.google.firebase.firestore.EventListener
cloudFirestoreManager.onPostsValuesChange()
  .observe(this, Observer(::onPostsUpdate))
fun stopListeningForPostChanges() = postsRegistration.remove()
override fun onStop() {
    super.onStop()
    cloudFirestoreManager.stopListeningForPostChanges()
}
Listening to Firetore Collection.
Mowqikunb ve Muleteve Makvixjuib.

Performing Queries

Sometimes, you don’t want to read only the documents of certain collections. Sometimes you need to filter out, match by values, or simply skip a certain amount of documents. To do this, you use database queries. Currently, you don’t have any nested documents in the posts collection. Up next, you’ll add comments to it to make it a bit more complex.

Adding Comments

Open CloudFirestoreManager.kt, and navigate to addComment(). Replace TODO with the following code:

// 1
val commentReference = database.collection(COMMENTS_COLLECTION).document()
// 2
val comment = HashMap<String, Any>()
// 3
comment[AUTHOR_KEY] = authenticationManager.getCurrentUser()
comment[CONTENT_KEY] = content
comment[POST_ID] = postId
comment[TIMESTAMP_KEY] = getCurrentTime()
// 4
commentReference
    .set(comment) // 5
    .addOnSuccessListener { onSuccessAction() } // 6
    .addOnFailureListener { onFailureAction() } // 7
cloudFirestoreManager.addComment(
            post.id,
            comment,
            ::onCommentSuccessfullyAdded,
            ::onCommentAddFailed
          )
The screen for creating a comment.
Zmu nwpuik xin jvaesacq i cirsoqx.

Comments Collection in Firestore Database.
Nugmipqp Rashikneeh ur Qesesxipu Cowufuwo.

Listening for comments

You can add comments to the database now, but you still can’t read them. Since you store comments in a separate collection from posts, to read them you’ll need to write a query that returns comments for the specific post. Every comment document has a post_id property that indicates to which post the comment belongs.

private lateinit var commentsRegistration: ListenerRegistration
// 1
commentsRegistration = database.collection(COMMENTS_COLLECTION)
    // 2
    .whereEqualTo(POST_ID, postId) // 3
    // 4
    .addSnapshotListener(EventListener { value, error ->
        if (error != null || value == null) {
            return@EventListener
        }
        if (value.isEmpty) {
            postsValues.postValue(emptyList())
        } else {
            val comments = ArrayList<Comment>()
            for (doc in value) {
                val comment = doc.toObject(Comment::class.java)
                comments.add(comment)
            }
            commentsValues.postValue(comments)
        }
    })
 post?.id?.let {postId ->
      cloudFirestoreManager.onCommentsValuesChange(postId)
        .observe(this, Observer(::onCommentsUpdate))
    }
fun stopListeningForCommentsChanges() = commentsRegistration.remove()
override fun onStop() {
    super.onStop()
    cloudFirestoreManager.stopListeningForCommentsChanges()
}
Adding Comments in Realtime.
Idnamk Calxongl ez Quusvoga.

Deleting comments

One last thing that you need to add is the ability to delete the comments. You’ll delete the comments for the particular posts when you delete that post.

// 1
database.collection(COMMENTS_COLLECTION)
    .whereEqualTo(POST_ID, postId)
    //2
    .get()
    //3
    .continueWith { task -> task.result?.documents?.forEach { it.reference.delete() } }
  deletePostComments(key)
Listening to Comments Updates.
Kikmalayq ci Qignovhm Aysepiz.

Working offline

Like Realtime Database, Firestore can also work offline. Cloud Firestore stores a copy of data that your app is using, locally, so that you can have access to the data if the device goes offline. You can perform operations like reading, writing and querying on the local copy. When your device goes back online, Firestore automatically syncs the data with the data that is stored remotely!

Other features

Cloud Firestore has many other features. You’ll go through some of them next.

Ordering and limiting

You’ve already seen how you can specify which documents you want to fetch from the collection by using whereEqualTo(). But there’s much more you can do, on top of whereEqualTo():

Pagination

You can have a lot of data stored in your database, but at times you don’t need all the data. Pagination allows you to split your database data into chunks so that you don’t need to fetch it all at once.

Indexing

To ensure good performance for every query, Firestore requires an index. Firestore automatically creates indices for the basic queries for you.

Key points

Where to go from here?

You covered a lot in this chapter. You learned how to read data from Firestore and listen for data changes in real-time. You also learned what queries are and how to use them only to fetch specific documents from a collection.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.

Unlock now