在从暂停的存储库中获取的 ViewModel 中传递 LiveData 的正确方法

Dom*_*ikS 6 kotlin android-livedata android-viewmodel kotlin-coroutines

我正在考虑 Kotlin 协程和 LiveData。我想做一个非常基本的用例,其中 ViewModel 返回从 Repository 挂起函数中获取的 LiveData,该函数也返回 LiveData。

存储库函数签名:

suspend fun getAll() : LiveData<List<Mountain>> 
Run Code Online (Sandbox Code Playgroud)

它不能简单地做到这一点:

fun getMountains() : LiveData<List<Mountain>> {
  return mountainsRepository.getAll()
}
Run Code Online (Sandbox Code Playgroud)

因为编译器声明挂起函数应该从协程或另一个挂起函数调用。我想出了两个丑陋的解决方案,但我知道它们并不优雅:

1 使用 runBlocking 的解决方案

fun getMountains() : LiveData<List<Mountain>> = runBlocking { mountainsRepository.getAll() }
Run Code Online (Sandbox Code Playgroud)

2 具有可为空 LiveData 的解决方案

fun getMountains() : LiveData<List<Mountain>>?{
    var mountains : LiveData<List<Mountain>>? = null
    viewModelScope.launch{
        mountains = mountainsRepository.getAll()
    }
    return mountains
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能正确地做到这一点?

Ale*_*fts 7

有一个liveData 构建器,可以在其主体中调用挂起函数。所以你的视图模型函数看起来像

fun getMountains() = liveData {
   emit(mountainsRepository.getAll()) 
}
Run Code Online (Sandbox Code Playgroud)

确保您至少使用

implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"

Run Code Online (Sandbox Code Playgroud)

正如 Lena 所提到的 -suspend从您的存储库getAll()功能中删除不会使其阻塞。

拥有

fun getAll() : LiveData<List<Mountain>> 
Run Code Online (Sandbox Code Playgroud)

在你的回购中,和

fun getMountains() = mountainsRepository.getAll()
Run Code Online (Sandbox Code Playgroud)

在您的视图模型中,可能是实现相同目标的更好方法

  • 如果您的 repo 函数返回 ``List&lt;Mountain&gt;`` 您只需将其发布到 liveData 或用户 ``liveData`` 构建器即可。如果您在一个函数签名中同时使用 suspend 和 livedata,那么您只需处理异步操作两次,并为自己带来额外的麻烦 (2认同)