如何在 OnCompleteListener Firebase 中使用异步/等待/协程

tom*_*fic 9 android kotlin firebase firebase-authentication kotlin-coroutines

我正在构建一个客户端应用程序,它使用 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
            }
       }
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,获取用户的 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
}

//......
Run Code Online (Sandbox Code Playgroud)

我尝试过阅读和实现协程,但我缺乏正确执行此操作的知识。

编辑

感谢@Doug Stevenson 的回答和指导,我已经成功构建了以下内容:

private suspend fun getUserIdToken(user: FirebaseUser) = coroutineScope {

    val job = async {
        user.getIdToken(false).result?.token
    }
    job.await()
}
Run Code Online (Sandbox Code Playgroud)

我以这种方式使用它:

fun updateDB(context: Context) = runBlocking {

    val user = FirebaseAuth.getInstance().currentUser

    if (user != null) {
        val token = getUserIdToken(user)
    }

  }
Run Code Online (Sandbox Code Playgroud)

这是正确的方法吗?由于下面给出的答案提出了不同的实现。

Dou*_*son 20

getIdToken异步返回一个Task对象。如果要在 Kotlin 协程中使用 Task 对象,可以使用库kotlinx-coroutines-play-services向 Task添加扩展方法await(),使其可以在协程中使用。这样,您就可以编写如下内容:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.9"
Run Code Online (Sandbox Code Playgroud)
import kotlinx.coroutines.tasks.await

suspend fun getIdTokenForUser(user: FirebaseUser): GetTokenResult {
    return try {
        user.getIdToken(false).await()
    }
    catch (e: Exception) {
        // handle error
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能必须在这里更新类型 - 我没有尝试编译或测试它。

也可以看看: