为什么我的存储库中的函数无法访问我的房间数据库中的数据

问题描述 投票:0回答:1

我在我的应用程序中创建了一个房间数据库,我可以使用我编写的函数向其中添加数据,但我无法检索它们。我的目标只是保存用户名和电子邮件并在修改时检索它们,以便我可以在 UI 中显示更改。问题是我的函数不检索信息,只是返回默认值,如 null 或空字符串。

这是我的实体:


@Entity
data class Info(
    val email: String,
    val userName: String,
    @PrimaryKey(autoGenerate = true)
    val id:Int = 0
)

这是我的道:


interface InfoDao {
    @Upsert
    suspend fun upsertInfo(info:Info)

    @Delete
    suspend fun deleteInfo(info:Info)

    @Query("SELECT userName FROM info LIMIT 1") 
    fun getUsernameAsLiveData(): LiveData<String>

    @Query("SELECT email FROM info LIMIT 1")
    fun getEmailAsLiveData(): LiveData<String>
}

我的存储库:


class Repo(private val db: InfoDatabase) {

    fun openDatabase() { 
        db.openHelper.writableDatabase
    }

    suspend fun upsertInfo(info: Info) {
        db.dao.upsertInfo(info)
    }

    suspend fun deleteInfo(info: Info) {
        db.dao.deleteInfo(info)
    }

    fun getUsername(): LiveData<String> {
        val usernameLiveData = db.dao.getUsernameAsLiveData()
        return usernameLiveData
    }

    fun getEmail(): LiveData<String> {
        return db.dao.getEmailAsLiveData()
    }
}

我的看法型号:


class RoomViewModel(private val repo: Repo) : ViewModel() {
    private val _isOpen = MutableStateFlow(false)
    val isOpen: StateFlow<Boolean> = _isOpen

    private val _usernameState = MutableLiveData<String?>()
    val usernameState: LiveData<String?> = _usernameState

    private val _emailState = MutableLiveData<String?>()
    val emailState: LiveData<String?> = _emailState

    fun openDatabase() {
        viewModelScope.launch {  
            repo.openDatabase()
            _isOpen.value = true  
    }
    suspend fun fetchData() {
        viewModelScope.launch {
            if (!isOpen.value) {
                repo.openDatabase()
            }

            val username = repo.getUsername().value
            _usernameState.value = username
            
            val email = repo.getEmail().value
            _emailState.value = email
        }
    }
    suspend fun upsertInfo(info: Info) {
        viewModelScope.launch {
            repo.upsertInfo(info)
        }
    }  

还有我的可组合项:


@Composable
fun DeviceScreen(
    navController: NavHostController,
    lifecycleOwner: LifecycleOwner,
    roomViewModel: RoomViewModel
) {
    val username by roomViewModel.usernameState.observeAsState()
    val email by roomViewModel.energyState.observeAsState()

    LaunchedEffect(Unit) {
        roomViewModel.openDatabase() //before this my roomDatabase was closed
    }

    LaunchedEffect(roomViewModel.isOpen) {
        roomViewModel.fetchData() 
    }


我希望在我的 logcat 中看到正常的电子邮件和用户名,也许是一个我可以使用的列表,但我得到的只是 null 或空字符串。我已将 Log 语句放在各处以尝试查明问题。起初我以为这是因为我的数据库在数据库检查器中关闭了,但我解决了这个问题,现在它是打开的。我可以看到我创建的虚拟用户名和电子邮件,但我仍然无法访问它们。我尝试过转换为流或简单字符串,但没有成功。我已经没有主意了。

kotlin android-jetpack-compose android-room
1个回答
0
投票

永远不要读取 LiveData 的

value
属性(除非您是在基于其先前值自动将其值更改为某个值的上下文中执行此操作)。 LiveData 直到将来的某个时刻才会包含从数据库读取的值,因此您必须观察它才能获取您想要的值。

ViewModel 中的

openDatabase()
函数也有问题,因为它启动一个协程并并行打开数据库,但您在实际打开之前将其标记为打开。但这并不重要,因为您根本不需要执行此操作即可使用 Room。

删除名为

openDatabase()
的两个函数以及
isOpen
流程。还要去掉
fetchData()
函数。这是不必要的卷积。相反,只需在声明站点直接将您的 LiveData 转换为 Flows,如下所示:

val usernameState = repo.getUsername().asFlow().stateIn(viewModelScope, null)

或者,要消除更多复杂性,只需将这些 LiveData 放入 DAO 和 repo 函数中的流中,这样您就可以删除此处的

asFlow()
部分。或者,将 ViewModel 属性设置为 LiveData 而不是 StateFlow,这样您就根本不需要进行任何转换。

© www.soinside.com 2019 - 2024. All rights reserved.