我试图在转换Map函数中调用数据库查询,并且遇到了各种错误。下面给出了我的项目代码的简化版本。
实体
@Entity(tableName = "category_table")
data class CategoryDatabase(
@PrimaryKey(autoGenerate = true)
var categoryId : Long = 0L,
@ColumnInfo(name="category_name")
var categoryName : String = ""
)
.
@Entity(tableName = "main_table")
data class MainDatabase(
@PrimaryKey(autoGenerate = true)
val mainId : Long = 0L,
@ColumnInfo(name="category_one")
val mainCategoryOne : Long = 0L
)
刀
@Query("SELECT category_name FROM CATEGORY_TABLE where categoryId= :categoryId")
suspend fun getCategoryNameById(categoryId: Long) : String
仓库
suspend fun getCategoryNameById(categoryId : Long) : String {
return databaseDao.getCategoryNameById(categoryId)
}
视图模型
在视图模型中,我查询了main_table并获得了数据。这存储在 readAllData 变量中,该变量的类型为 LiveData〈List< MainDatabase >〉。主表包含类别ID。我想使用transformation.map来获取类别名称。我在视图模型中实现了以下内容。
suspend fun getName(categoryId: Long) : String{
val d : Deferred<String> = viewModelScope.async {
repository.getCategoryNameById(categoryId)
}
return d.await()
}
然后在init中添加
init{
..
..
..
listTransformed = Transformations.map(readAllData)
{ list ->
list.map {
viewModelScope.launch {
getName(it.mainCategoryOne)
}
}
}
}
我想我需要使用async和await,因为我需要等待结果。这使得 getName 成为一个挂起函数,因此只能在协程中启动。然而,当像上面的代码一样启动它时,我得到一个错误
Type Mismatch.
Required: String
Found : Job
如果我尝试在没有协程的情况下调用查询,应用程序会崩溃,因为我正在尝试从主UI调用数据库。这里正确的方法是什么?或者有更简单的方法来解决这个问题?
谢谢你
1条答案
按热度按时间eyh26e7m1#
立即在Deferred上调用
await()
意味着在第一时间调用async
是没有意义的。“Await”意味着同步等待异步结果,那么为什么你首先要使它异步呢?你可以如下修改你的函数以获得相同的行为,而不需要复杂的东西:你不能像这样混合和匹配LiveData和协程。你的
map
lambda函数是启动协程并返回结果协程Jobs,所以最终结果是LiveData<List<Job>>
。Job不返回任何东西,所以它在这个目的上是无用的。你可以使用async
而不是launch
,然后你会有一个LiveData<List<Deferred<String>>>
,在观察者中你可以启动一个协程,并在上面调用async()
来解包这些值。可能不是你想要的,因为那是复杂的。相反,我会转换为Flow,这样你就可以在Map函数中调用suspend函数,然后如果你想坚持使用LiveData,你可以将它转换回LiveData。在内部Map中,你可以使用
async
和awaitAll
来并行Map列表中的项。我们使用coroutineScope { }
来对子协程而不是兄弟协程来完成这一任务。就像这样:编辑:我想我有点跑题了。因为这是一个数据库,如果你写一个DAO函数来做这件事,会更高效,更简单。
假设
allData
在你的DAO中是这样的:然后你可以像这样写另一个DAO函数: