在 Kotlin 协程中等待 LiveData 结果

nsk*_*nsk 4 android kotlin android-livedata kotlin-coroutines

我有一个带有异步方法的存储库类,返回User包装成一个LiveData

interface Repository {
    fun getUser(): LiveData<User>
}
Run Code Online (Sandbox Code Playgroud)

在 ViewModel 的 couotine 范围中,我想等待getUser()方法的结果并使用User实例。

这就是,我正在寻找:

private fun process() = viewModelScope.launch {
   val user = repository.getUser().await()
   // do something with a user instance
}
Run Code Online (Sandbox Code Playgroud)

我找不到LiveData<>.await()扩展方法,以及任何实现它的尝试。所以在我自己做之前,我想知道也许有更好的方法吗?

我发现所有的解决方案都有关使getUser()一个suspend方法,但如果我不能改变什么Repository

Com*_*are 7

您应该能够await()使用suspendCancellableCoroutine(). 这可能不完全正确,但应该按照以下方式工作:

public suspend fun <T> LiveData<T>.await(): T {
  return withContext(Dispatchers.Main.immediate) {
    suspendCancellableCoroutine { continuation ->
      val observer = object : Observer<T> {
        override fun onChanged(value: T) {
          removeObserver(this)
          continuation.resume(value)
        }
      }

      observeForever(observer)

      continuation.invokeOnCancellation {
        removeObserver(observer)
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这应该返回 发出的第一个值LiveData,而不会留下观察者。

  • 由于 `continuation.invokeOnCancellation()` 可以在任何线程上调用,因此在调用 `removeObserver(observer)` 之前通过在 Handler 上发布消息来确保我们位于主线程上非常重要 (2认同)