如何让 Kotlin 中的 runBlocking 正常工作?

问题描述 投票:0回答:1

我的目标是让 loadInformationFromFirestore(从 Firestore 数据库读取数据)在执行其后的代码(此处只是 Timber 日志记录消息)之前完成。当我运行 getGroupSummaries 时,这些是我看到的日志消息:

runBlocking 中 loadUserInformationFromFirestore 之后

runBlocking 后 loadUserInformationFromFirestore 后

在从Firestore加载用户信息

这对我来说“runBlocking”根本没有阻塞——runBlocking 在 LoadUserInformationFromFirestore 完成之前返回。任何建议将不胜感激。

var mFirestore: FirebaseFirestore? = null

fun getGroupSummaries(groupInfo: GroupInformation, adminUserInfo: UserInformation) {
    mFirestore = FirebaseFirestore.getInstance()

    val uid = "3iHWCsGmKvfq4w9OgDNWZsSs8wy2"

    runBlocking {
        val loadUserInformationJob = viewModelScope.launch { loadUserInformationFromFirestore(uid) }
        loadUserInformationJob.join()
        Timber.d("After loadUserInformationFromFirestore in runBlocking")
    }
    Timber.d("After loadUserInformationFromFirestore after runBlocking")
}

suspend fun loadUserInformationFromFirestore(uid: String) {
    try {
        // Get document from Firestore
        val docRef =
            mFirestore!!.collection("Users").document(uid).collection("UserProfile").document(uid)

        docRef.get().addOnCompleteListener { task ->
            if (task.isSuccessful) {
                val document = task.result
                if (document.exists()) {
                    Timber.d("In LoadUserInformationFromFirestore")
                } else if (!document.exists()) {
                    Timber.e(
                        "In LoadInformationFromFirestore, User document does not exist. Send user through into questions."
                    )
                } else {
                    Timber.e("In LoadInformationFromFirestore, Error loading user document")
                }
            } else {
                Timber.e(
                    "In LoadInformationFromFirestore, get Firestore failed with ",
                    task.exception
                )
            }
        }
    } catch (e: Exception) {
        Timber.w("Error getting Firebase User", e)
    }
}
kotlin kotlin-coroutines blocking
1个回答
1
投票

我认为该问题与 Firestore 回调的异步性质有关。

addOnCompleteListener
内部的
loadUserInformationFromFirestore
回调是异步的,runBlocking不会等待它完成。

您可以使用

suspendCoroutine
suspendCancellableCoroutine
将异步 Firestore 任务转换为可挂起的协程。这样,您可以确保 runBlocking 协程将等待 Firestore 任务完成后再继续。

看这里:

var mFirestore: FirebaseFirestore? = null

fun getGroupSummaries(groupInfo: GroupInformation, adminUserInfo: UserInformation) {
    mFirestore = FirebaseFirestore.getInstance()

    val uid = "3iHWCsGmKvfq4w9OgDNWZsSs8wy2"

    runBlocking {
        try {
            val userInformation = loadUserInformationFromFirestore(uid)
            Timber.d("After loadUserInformationFromFirestore in runBlocking")
        } catch (e: Exception) {
            Timber.e("Error loading user information", e)
        }
    }
    Timber.d("After loadUserInformationFromFirestore after runBlocking")
}

suspend fun loadUserInformationFromFirestore(uid: String): UserInformation = suspendCancellableCoroutine { continuation ->
    try {
        // Get document from Firestore
        val docRef =
            mFirestore!!.collection("Users").document(uid).collection("UserProfile").document(uid)

        docRef.get().addOnCompleteListener { task ->
            if (task.isSuccessful) {
                val document = task.result
                if (document.exists()) {
                    Timber.d("In LoadUserInformationFromFirestore")
                    // Assuming UserInformation is a class you want to return
                    continuation.resume(UserInformation(/* populate with data */))
                } else {
                    Timber.e("In LoadInformationFromFirestore, User document does not exist.")
                    continuation.resumeWithException(DocumentNotFoundException("User document not found"))
                }
            } else {
                Timber.e("In LoadInformationFromFirestore, get Firestore failed with ", task.exception)
                continuation.resumeWithException(task.exception ?: RuntimeException("Unknown error"))
            }
        }
    } catch (e: Exception) {
        Timber.w("Error getting Firebase User", e)
        continuation.resumeWithException(e)
    }
}

class DocumentNotFoundException(message: String) : RuntimeException(message)

这里,runBlocking 协程将等待 Firestore 任务完成,然后再进入下一行。此外,它还处理异常并提供更结构化的返回结果的方式。

希望有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.