Android 房间 - 来自 SELECT 查询的 Return 行

Android Room - Return Row from SELECT Query

我正在使用 Android Room 构建离线数据库。我能够执行简单的 INSERT 或 DELETE 查询,但我很难弄清楚如何使用 returns 一行的参数执行 SELECT。这是我现在的代码:

users_details table:

@Entity(tableName = "user_details")
data class User(
    @PrimaryKey(autoGenerate = true)
    val userId: Int,
    var email : String,
    val userName: String = "NoName",
)

道:

@Dao
interface UserDao {
    @Query("SELECT * FROM user_details WHERE email =:email LIMIT 1")
    suspend fun findByEmail(email: String) : User
}

存储库:

class UserRepository(private val userDao: UserDao) {
    suspend fun findUserByEmail(email: String): User {
        return userDao.findByEmail(email)
   }
}

视图模型:

class UserViewModel(application: Application) : AndroidViewModel(application) {

    val _user = MutableLiveData<User>()
    val user: LiveData<User>
        get() = _user

    fun findUserByEmail(email: String) {
        viewModelScope.launch {
                val userByEmail = repository.findUserByEmail(email)
                _user.value = userByEmail
                Log.d("ViewModel", _user.value.toString())  <--HERE LIVEDATA RESULTS UPDATED AND USER RESULTS LOADED FROM ROOM TABLE
            }
    }
}

UI撰写

@Composable
fun Screen(navController: NavController, UserViewModel : UserViewModel) {

//CODE FOR GOOGLE-SIGNIN - CODE OUTPUT is "username" and "useremail" in a user object


    //Support variable for observing LiveData in UserViewModel
    val lifecycleOwner = LocalLifecycleOwner.current

    //Manage next Navigation element based on/if the user is already recorded in Room DB
    user?.let {

        LaunchedEffect(key1 = true) {

            navController.popBackStack()

            //Check if email used to log-in is already in Database
            val isUserInDatabase = mUserViewModel.readAllData.value?.
            find { user -> user.email == it.email }

            //If it doesn't exist in DB go to FirstLoginScreen to create user
            if (isUserInDatabase == null) {
                navController.navigate("firstlogin")
            }

            //If it exists load user details and continue to MainScreen
            else {
                mUserViewModel.findUserByEmail(it.email!!)
                mUserViewModel.user.observe(lifecycleOwner) {
                    navController.navigate("main")
                }
            }
        }
    }

        

我已经阅读了很多类似的帖子,但没有人能够让我完全理解哪里出了问题。 我也尝试使用 LiveData<User>,但我肯定做错了,因为即使 table 中的数据存在,我也总是得到空数据(使用 Log 进行检查)

编辑:感谢@CommonsWare 的评论,我已经能够理解主要问题与在 mainThread 中使用这些调用有关。我已经能够避免实施 viewModelScope.launch() 的崩溃。不幸的是,我仍然无法获得我想要的结果。上面的代码已更新。

我找到了解决办法。问题是由行的定位引起的:

navController.popBackStack()

这一行的正确位置就在navController.navigate("screen")之前,像这样:

user?.let {

        LaunchedEffect(key1 = true) {

            //navController.popBackStack() //<- IN THIS POSITION CODE DOESN'T WORK!!!!

            //Check if email used to log-in is already in Database
            val isUserInDatabase = mUserViewModel.readAllData.value?.
            find { user -> user.email == it.email }

            //If it doesn't exist in DB go to FirstLoginScreen to create user
            if (isUserInDatabase == null) {
                navController.popBackStack() //<---HERE IS GOOD!
                navController.navigate("firstlogin")
            }

            //If it exists load user details and continue to MainScreen
            else {
                mUserViewModel.findUserByEmail(it.email!!)
                mUserViewModel.user.observe(lifecycleOwner) {
                    navController.popBackStack() //<---HERE IS GOOD!
                    navController.navigate("main")
                }
            }
        }

我还是不明白为什么旧代码不起作用。特别是我不明白为什么下面的代码 popBackStack() 方法运行正常(即 mUserViewModel.findUserByEmail(it.email!!) 被调用)但我没有得到 LiveData 更新。希望高手们给个解释