如何将Kotlin Coroutines与Firestore查询

发布于 2025-02-03 04:23:42 字数 3258 浏览 3 评论 0原文

我已经创建了一个使用kotlinfirebase firestore的应用程序。现在,我需要实现Coroutines,因为主线程上有很多工作。但是我也是初学者,所以这对我来说是新事物。我已经在此上观看了一些教程,但是我没有在firestore上找到完整的教程带有coroutines。因此,我需要一些帮助来在我的应用程序中以这样的部分实现Coroutines(我是我自己尝试的,但没有得到)。

从Firestore检索帖子。

private fun retrievePosts() {
             FirebaseFirestore.getInstance().collection("Posts")
            .orderBy("timeStamp", Query.Direction.DESCENDING)
            .get()
            .addOnSuccessListener { queryDocumentSnapshots ->
                postList?.clear()
                for (documentSnapshot in queryDocumentSnapshots) {
                    val post = documentSnapshot.toObject(Post::class.java)
                    postList?.add(post)
                }
                postAdapter?.notifyDataSetChanged()
                postAdapter?.setOnPostClickListener(this)
                if (isRefreshed) {
                    swipe_refresh_home?.setRefreshing(false)
                    isRefreshed = false
                }
                swipe_refresh_home?.visibility = VISIBLE
                progress_bar_home?.visibility = GONE
            }.addOnFailureListener { e ->
                Log.d(TAG, "UserAdapter-retrieveUsers: ", e)
                swipe_refresh_home?.visibility = VISIBLE
                progress_bar_home?.visibility = GONE
            }
    }

将用户数据输入适配器

private fun userInfo( fullName: TextView, profileImage: CircleImageView,
                      about: TextView, uid: String,
                      userLocation: TextView, itemRoot: LinearLayout ) {

        val userRef = FirebaseFirestore.getInstance().collection("Users").document(uid)
        userRef.get()
                .addOnSuccessListener {
                    if (it != null && it.exists()) {
                        val user = it.toObject(User::class.java)
                        Glide.with(mContext).load(user?.getImage()).placeholder(R.drawable.default_pro_pic).into(profileImage)

                        fullName.text = user?.getFullName().toString()

                        about.text = user?.getAbout()

                        if (user?.getLocation() != ""){
                            userLocation.visibility = VISIBLE
                            userLocation.text = user?.getLocation()
                        }

                        if (profileImage.drawable == null){
                            itemRoot.visibility = GONE
                        }
                        else{
                            itemRoot.visibility = VISIBLE
                        }
                    }
                }
    }

,并将此保存发布按钮放入适配器中。

private fun savedPost(postId: String, saveButton: ImageView?) {
        FirebaseFirestore.getInstance().collection("Users").document(currentUserID)
                .collection("Saved Posts").document(postId)
                .get()
                .addOnSuccessListener {
                    if (it.exists()) {
                        saveButton?.setImageResource(drawable.ic_bookmark)
                    } else {
                        saveButton?.setImageResource(drawable.bookmark_post_ic)
                    }
                }
    }

I have created an app with Kotlin and Firebase Firestore. Now I need to implement coroutines as there is so much work on the main thread. But I'm also a beginner so it's something new to me. I've watched some tutorials on this but I didn't find complete tutorials on Firestore with coroutines. So I need some help to implement coroutines in my app In such parts like these (I tried by myself but didn't get it).

Retrieving posts from Firestore.

private fun retrievePosts() {
             FirebaseFirestore.getInstance().collection("Posts")
            .orderBy("timeStamp", Query.Direction.DESCENDING)
            .get()
            .addOnSuccessListener { queryDocumentSnapshots ->
                postList?.clear()
                for (documentSnapshot in queryDocumentSnapshots) {
                    val post = documentSnapshot.toObject(Post::class.java)
                    postList?.add(post)
                }
                postAdapter?.notifyDataSetChanged()
                postAdapter?.setOnPostClickListener(this)
                if (isRefreshed) {
                    swipe_refresh_home?.setRefreshing(false)
                    isRefreshed = false
                }
                swipe_refresh_home?.visibility = VISIBLE
                progress_bar_home?.visibility = GONE
            }.addOnFailureListener { e ->
                Log.d(TAG, "UserAdapter-retrieveUsers: ", e)
                swipe_refresh_home?.visibility = VISIBLE
                progress_bar_home?.visibility = GONE
            }
    }

Getting user data into an adapter

private fun userInfo( fullName: TextView, profileImage: CircleImageView,
                      about: TextView, uid: String,
                      userLocation: TextView, itemRoot: LinearLayout ) {

        val userRef = FirebaseFirestore.getInstance().collection("Users").document(uid)
        userRef.get()
                .addOnSuccessListener {
                    if (it != null && it.exists()) {
                        val user = it.toObject(User::class.java)
                        Glide.with(mContext).load(user?.getImage()).placeholder(R.drawable.default_pro_pic).into(profileImage)

                        fullName.text = user?.getFullName().toString()

                        about.text = user?.getAbout()

                        if (user?.getLocation() != ""){
                            userLocation.visibility = VISIBLE
                            userLocation.text = user?.getLocation()
                        }

                        if (profileImage.drawable == null){
                            itemRoot.visibility = GONE
                        }
                        else{
                            itemRoot.visibility = VISIBLE
                        }
                    }
                }
    }

And this Save post button in an adapter.

private fun savedPost(postId: String, saveButton: ImageView?) {
        FirebaseFirestore.getInstance().collection("Users").document(currentUserID)
                .collection("Saved Posts").document(postId)
                .get()
                .addOnSuccessListener {
                    if (it.exists()) {
                        saveButton?.setImageResource(drawable.ic_bookmark)
                    } else {
                        saveButton?.setImageResource(drawable.bookmark_post_ic)
                    }
                }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

春夜浅 2025-02-10 04:23:42

当我看到您的代码时,您正在使用以下查询:

val queryPostsByTimestamp = FirebaseFirestore.getInstance().collection("Posts")
        .orderBy("timeStamp", Query.Direction.DESCENDING)

很可能是从“帖子”集合中获取帖子对象列表。

为了使用 kotlin coroutines ,不要忘记在gradle中添加以下依赖项(应用程序)文件:

 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.9"
 implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
 implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"

我将使用MVVM架构模式为您提供解决方案。因此,我们将使用存储库类和ViewModel类。对于对Firestore的异步调用,我们将使用 flow

对于我们从数据库调用中获得的响应,我们需要一个看起来像这样的密封类:

sealed class Response<out T> {
    class Loading<out T>: Response<T>()

    data class Success<out T>(
        val data: T
    ): Response<T>()

    data class Failure<out T>(
        val errorMessage: String
    ): Response<T>()
}

假设您有一个“帖子”类,让我们在存储库类中创建以下功能:

fun getPostsFromFirestore() = flow {
    emit(Loading())
    emit(Success(queryPostsByTimestamp.get().await().documents.mapNotNull { doc ->
        doc.toObject(Post::class.java)
    }))
}. catch { error ->
    error.message?.let { errorMessage ->
        emit(Failure(errorMessage))
    }
}

因此,我们将根据对象进行启动国家。首次调用该函数时,我们使用emit(loading(),当我们获取数据时,我们发出list&lt; post&gt;,并且 errormessage)发出错误消息

一个错误,我们使用fafer (

fun getPosts() = liveData(Dispatchers.IO) {
    repository.getPostsFromFirestore().collect { response ->
        emit(response)
    }
}

。 )函数调用,我们将结果进一步散发为livedata对象,因此可以在这样的活动/片段中观察到:

private fun getPosts() {
    viewModel.getPosts().observe(this, { response ->
        when(response) {
            is Loading -> //Load a ProgessBar
            is Success -> {
                val postList = response.data
                //Do what you need to do with your list
                //Hide the ProgessBar
            }
            is Failure -> {
                print(response.errorMessage)
                //Hide the ProgessBar
            }
        }
    })
}

这几乎就是其中的大部分!

As I see your code, you are using the following query:

val queryPostsByTimestamp = FirebaseFirestore.getInstance().collection("Posts")
        .orderBy("timeStamp", Query.Direction.DESCENDING)

Most probably to get a list of Post objects from your "Posts" collection.

In order to use Kotlin Coroutines, don't forget to add the following dependencies in the Gradle (app) file:

 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.9"
 implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
 implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"

I'll provide you a solution using the MVVM architecture pattern. So we'll use a repository class and a ViewModel class. For the asynchronous calls to Firestore, we'll use Flow.

For the response that we get from the database call, we need a sealed class that looks like this:

sealed class Response<out T> {
    class Loading<out T>: Response<T>()

    data class Success<out T>(
        val data: T
    ): Response<T>()

    data class Failure<out T>(
        val errorMessage: String
    ): Response<T>()
}

Assuming that you have a "Post" class, let's create in the repository class the following function:

fun getPostsFromFirestore() = flow {
    emit(Loading())
    emit(Success(queryPostsByTimestamp.get().await().documents.mapNotNull { doc ->
        doc.toObject(Post::class.java)
    }))
}. catch { error ->
    error.message?.let { errorMessage ->
        emit(Failure(errorMessage))
    }
}

So we'll emit an object according to the state. When first-time calling the function, we emit a loading state using emit(Loading(), when we get the data we emit the List<Post> and if we get an error, we emit the error message using Failure(errorMessage).

Now we need to call this function, from the ViewModel class:

fun getPosts() = liveData(Dispatchers.IO) {
    repository.getPostsFromFirestore().collect { response ->
        emit(response)
    }
}

With the above function, we collect the data that we get from the getPostsFromFirestore() function call, and we emit the result further as a LiveData object so it can be observed in the activity/fragment like this:

private fun getPosts() {
    viewModel.getPosts().observe(this, { response ->
        when(response) {
            is Loading -> //Load a ProgessBar
            is Success -> {
                val postList = response.data
                //Do what you need to do with your list
                //Hide the ProgessBar
            }
            is Failure -> {
                print(response.errorMessage)
                //Hide the ProgessBar
            }
        }
    })
}

That's pretty much of it!

西瓜 2025-02-10 04:23:42

我不知道firebase,所以我可能会错过一些东西,但是总的来说,您不需要图书馆中的特殊支持即可与Coroutines一起使用。如果您启动背景Coroutine,然后在其中执行上述代码,则Firebase可能会在您的Coroutine内运行而不会出现任何问题。

唯一有问题的部分可能是听众。一些Libs在线程中调用用于执行它们的线程的回调,但对特定线程进行了一些调度回调。在火箱的情况下,默认情况下,它在主线程中运行听众。如果这不是您想要的,则可以通过执行人通过coroutines内的回调,例如:

.addOnSuccessListener(Dispatchers.Default.asExecutor()) { ... }

I don't know Firebase, so I may miss something, but generally speaking you don't need a special support in the library to use it with coroutines. If you start a background coroutine and then execute your above code in it, then Firebase will probably run within your coroutine without any problems.

The only problematic part could be listeners. Some libs invoke callbacks in the thread that was used to execute them, but some dispatch callbacks to a specific thread. In the case of Firebase it seems by default it runs listeners in the main thread. If this is not what you want, you can pass an executor to run callbacks within coroutines as well, e.g.:

.addOnSuccessListener(Dispatchers.Default.asExecutor()) { ... }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文