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
更新。希望高手们给个解释
我正在使用 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
更新。希望高手们给个解释