[英]How To Use Async/Await/Coroutines In OnCompleteListener Firebase
我正在構建一個客戶端應用程序,它使用 Firebase 做兩件事:
我設法在我的客戶端和后端服務器上正確設置了所有內容(使用 Firebase 的 Admin SDK),並且能夠正確驗證用戶並允許他們讀/寫數據庫。
我還使用 Retrofit2 將請求從客戶端發送到后端。
作為允許用戶訪問數據庫的一部分,需要將用戶的令牌發送到后端,以便可以驗證用戶。
為此,我有以下邏輯:
val user = FirebaseAuth.getInstance().currentUser
if (user != null) {
user.getIdToken(false).addOnCompleteListener {
if (it.isSuccessful) {
val token = it.result?.token
//retrofit logic to send request happens from here
}
}
如您所見,獲取用戶的 Id 令牌是一個異步調用,在我擁有的當前代碼庫中,我對后端的每個調用(重復)都有這個代碼塊。
我想知道如何將這個片段導出到一個函數(也許是一個掛起方法?),以便它可以在每次調用后端時重復使用
我在網上搜索並看到了很多 SO 問題,但沒有一個適合這種情況。 我想過傳入回調,但是我有幾個方法與后端通信,每個方法都需要不同的回調方法。
我正在尋找的解決方案如下所示:
fun fetchDataFromDB() {
getIdTokenForUser()
//wait till it finishes and then
//perform request to DB
}
fun updateDataInDB() {
getIdTokenForUser()
//wait till it finishes and then
//perform request to DB
}
//......
我曾嘗試閱讀和實現協程,但我缺乏正確執行此操作的知識。
編輯
感謝@Doug Stevenson 的回答和指導,我設法構建了以下內容:
private suspend fun getUserIdToken(user: FirebaseUser) = coroutineScope {
val job = async {
user.getIdToken(false).result?.token
}
job.await()
}
我以這種方式使用它:
fun updateDB(context: Context) = runBlocking {
val user = FirebaseAuth.getInstance().currentUser
if (user != null) {
val token = getUserIdToken(user)
}
}
這是正確的方法嗎? 由於下面給出的答案提出了不同的實現。
getIdToken
是異步返回一個 Task 對象。 如果您想在 Kotlin 協程中使用 Task 對象,您可以使用庫kotlinx-coroutines-play-services向 Task 添加一個擴展方法await()
,使其在協程中可用。 有了這個,你可以寫這樣的東西:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.9"
import kotlinx.coroutines.tasks.await
suspend fun getIdTokenForUser(user: FirebaseUser): GetTokenResult {
return try {
user.getIdToken(false).await()
}
catch (e: Exception) {
// handle error
}
}
您可能需要在這里更新類型 - 我沒有嘗試編譯或測試它。
也可以看看:
為了從基於回調的 API 開始,如下所示:
val myCallback = object : ServiceCallback() {
override fun onResult(theobject: Something) {
// your callback code here
}
override fun onFailure(ex: Throwable) {
// error handling
}
}
theService.enqueue(callback)
您可以使用suspendCoroutine
它的作用是暫停執行,直到回調滿足延續。 所以你可以像下面這樣寫一個 KTX:
suspend fun Service.getSomething(): Something = suspendCoroutine{ cont ->
val callback = object : ServiceCallback(){
override fun onSuccess(data: Something): Unit = cont.resume(data)
override fun onFailure(ex: Throwable): Unit = cont.resume(ex)
}
this.enqueue(callback)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.