Android-通过ID从房间数据库中检索项目



我正试图从我的Room数据库中检索一个客户端项目。每个客户端都显示在一个列表中,每个客户端上都有一个编辑按钮。当按下按钮时,我想通过他们的id从数据库中检索该客户端。然后,他们的详细信息将显示在编辑屏幕上。

我的问题出现在实际从数据库获取客户端的过程中。到目前为止,我已经尝试了两种方法:

基于推论的方法

我已经尝试使用Room中基于协同程序的函数来检索该项目。这种方法在一定程度上确实"有效",但在其当前形式中,协同程序最终会在***显示编辑屏幕后检索新搜索的客户端***。这样,当您编辑客户端时,您最终会编辑之前尝试编辑的客户端。我曾试图通过使用.join((、使用viewModelScope.async而不是launch、然后尝试使用.await以及其他一些想法来抵消这一点,但都没有奏效。

ClientDao.kt

@Dao
interface ClientDao {
@Query("SELECT * FROM tblClient WHERE id = :id")
suspend fun getClientToEdit(id: Int): List<Client>
}

ClientRepository.kt

class ClientRepository(private val clientDao: ClientDao) {
val clientSearchResults = MutableLiveData<List<Client>>() 
suspend fun getClientToEdit(id: Int) {
clientSearchResults.value = clientDao.getClientToEdit(id)
}
}

ClientViewModel.kt

class ClientViewModel(application: Application): ViewModel() {
private val repository: ClientRepository
val clientSearchResults: MutableLiveData<List<Client>>
init {
val clientDB = ManagementDatabase.getDatabase(application)
val clientDao = clientDB.clientDao()
repository = ClientRepository(clientDao)
clientSearchResults = repository.clientSearchResults
}
fun getClientToEdit(clientId: Int) = viewModelScope.launch {
repository.getClientToEdit(clientId)
}
}

ManagementApp.kt

ClientScreen(
onEditClient = { id ->
clientViewModel.getClientToEdit(id)
val editClientList: List<Client>? = clientViewModel.clientSearchResults.value
//This looks awful but it works
// It just gets the client details of the selected client
if (editClientList != null) {
if (editClientList.firstOrNull() != null) {
selectedClient = editClientList[0]

如果我能找到一种方法,使clientViewModel.getClientToEdit(id)在ManagementApp.kt中运行其余代码之前完全执行,它就会起作用。问题是我不知道怎么做。

基于流程的方法:

我真的不认为这种方法会奏效,但它值得一试。我尝试使用流列表来检索项目,就像检索整个列表一样。ClientDao.kt

@Dao
interface ClientDao {
@Query("SELECT * FROM tblClient WHERE id = :id")
fun getClientToEdit(id: Int): Flow<List<Client>>
}

ClientRepository.kt

class ClientRepository(private val clientDao: ClientDao) {
fun getClientSearchResults(id: Int): Flow<List<Client>> =
clientDao.getClientToEdit(id)
}

ClientViewModel.kt

class ClientViewModel(application: Application): ViewModel() {
private val repository: ClientRepository

init {
val clientDB = ManagementDatabase.getDatabase(application)
val clientDao = clientDB.clientDao()
repository = ClientRepository(clientDao)
}

fun getClientToEdit(clientId: Int): LiveData<List<Client>> {
return repository.getClientSearchResults(id = clientId).asLiveData()
}
}

ManagementApp.kt

ClientScreen(
onEditClient = { id ->
val editClientList by clientViewModel.getClientToEdit(id).observeAsState(listOf())
//This looks awful but it works
// It just gets the client details of the selected client
if (editClientList != null) {
if (editClientList.firstOrNull() != null) {
selectedClient = editClientList[0]

这种方法的问题在于,.obsobserveAsState给了我"@Composable调用只能在@Composable函数的上下文中发生"错误(尽管上面的代码片段实际上在@Composble函数中(。

如果有人能提供一些急需的帮助,我将不胜感激。我是安卓系统的新手,在Room方面遇到过很多困难,所以如果代码没有达到标准,我很抱歉。非常感谢。

当按下按钮时,我想通过他们的id从数据库中检索该客户端。然后,他们的详细信息将显示在编辑屏幕上。

如果通过";编辑屏幕";你指的是使用ViewModel(例如androidx.navigation(导航到的正确屏幕,更好的方法是将id传递到新屏幕,并在其ViewModel中加载。

如果我能找到一种方法,使clientViewModel.getClientToEdit(id)在运行ManagementApp.kt 中的其余代码之前完全执行

您可以通过使getClientToEdit暂停有趣,然后执行以下操作来做到这一点:

val scope = rememberCoroutineScope()
ClientScreen(
onEditClient = { id ->
scope.launch {
clientViewModel.getClientToEdit(id)
// now getClientToEdit was executed
}
}
)

我还建议直接从getClientToEdit返回Client,使用LiveData,因为这不是必需的

尽管上面的代码片段实际上在@Composable函数中

不是,您正试图从onClick回调调用它,而onClick没有用@Composable标记,因此您无法从那里调用可组合函数。


总结一下:
如果您的操作结果是导航到另一个屏幕,您可以执行以下操作之一:

  1. 按照我的建议,只将id传递到另一个屏幕并在那里加载
  2. onEditClient回调中启动协同程序,加载客户端并从那里导航,如上所示
  3. 在ViewModel中加载客户端,在那里更新一些状态,并根据该状态进行导航,例如:
// ViewModel
val actions = MutableSharedFlow<Action>()
fun editClient(id: Int) = viewModelScope.launch {
val client = repository.getClientToEdit(clientId)
actions.emit(NavigateToEditScreen(client))
}
// Screen
val action by clientViewModel.actions.collectAsState()
LaunchedEffect(action) {
if (action is NavigateToEditScreen) {
// do the navigation using action.client
}
}
ClientScreen(
onEditClient = { id ->
clientViewModel.editClient(id)
}
)

最新更新