android - Android Room getById(id: Int) 查询从第一个片段调用时返回一个有效对象,但从所有其他片段调用时返回 null
问题描述
我正在做我的学校项目,我开始出现这种奇怪的房间行为。我不得不承认,过去一切都可以正常工作,但是在更改了一些东西之后它停止了,现在即使我将几乎所有东西都恢复到原来的位置,它也无法正常工作。
这是我的 UserDao.kt:
@Dao
interface UserDao {
@Query("SELECT * FROM $USER_TABLE_NAME")
fun getAll(): LiveData<List<User>>
@Query("SELECT * FROM $USER_TABLE_NAME WHERE id = :id")
fun getById(id: Int): LiveData<User>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(user: User)
@Update
fun update(user: User)
@Query("UPDATE $USER_TABLE_NAME SET pictureAddress = :image WHERE id = :id")
fun updateImageWhereId(id: Int, image: String)
@Delete
fun delete(user: User)
}
这是 LoginFragment.kt,第一个片段,在应用程序启动时被加载。在这里,我检查数据库中是否有用户,如果有,我检查密码是否匹配。这是查询返回它应该返回的用户的地方,并且一切正常。
class LoginFragment : Fragment() {
private lateinit var binding: FragmentLoginBinding
private lateinit var model: MainViewModel
private val navigation: INavigationCallback by lazy {
activity as INavigationCallback
}
data class IdPassword(var id: String = "", var password: String = "", var isCorrect: Boolean = true)
private val idPassword: IdPassword = IdPassword()
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? =
DataBindingUtil.inflate<FragmentLoginBinding>(inflater,
R.layout.fragment_login,
container, false).run {
binding = this
model = activity!!.let {
ViewModelProviders
.of(it, MainViewModel.Factory(it.application))
.get(MainViewModel::class.java)
}
lifecycleOwner = this@LoginFragment
idPassword = this@LoginFragment.idPassword
navigation = this@LoginFragment.navigation
applyLoginButton.setOnClickListener { tryLogin() }
return root
}
private fun tryLogin() {
//databaseData.getUserById - is basically a wrapper
model.databaseData.getUserById(idPassword.id.toInt()).observe(activity!!, Observer {
if(it != null && it.password == idPassword.password){
model.activeUserId = it.id //this stores active user's id
navigation.navigateTo(R.id.action_loginFragment_to_mainMenuFragment)
} else {
binding.errorLogin.visibility = View.VISIBLE
}
})
}
}
登录成功后,我们进入主菜单屏幕,在这里我需要再次获取用户,以显示他的姓名和头像。这是MainMenuFragment.kt,与上面相同的查询返回 null 的地方。我也尝试对此进行测试,因此请阅读评论以更好地理解我所做的事情:
class MainMenuFragment : Fragment() {
private lateinit var binding: FragmentMainMenuBinding
private val viewEffect: MainMenuViewUtils by lazy {
MainMenuViewUtils(binding.userNameSmall, binding.mainLinearLayoutTitle)
}
private val globalLayoutListener = object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
binding.root.viewTreeObserver.removeOnGlobalLayoutListener(this)
viewEffect.adjustCardSize(activity!!, binding.todayStatsCard)
}
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? = DataBindingUtil
.inflate<FragmentMainMenuBinding>(inflater,
R.layout.fragment_main_menu,
container, false).run {
binding = this
lifecycleOwner = this@MainMenuFragment
navigation = activity as INavigationCallback
viewModel = activity!!.let {
ViewModelProviders
.of(it, MainViewModel.Factory(it.application))
.get(MainViewModel::class.java)
}
viewModel?.let {
user = it.activeUser
it.setUpMainMenuObservers()
}
mainMenuAppbar.addOnOffsetChangedListener(
AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
viewEffect.onOffsetChanged(appBarLayout, verticalOffset)
})
profilePicture.setOnClickListener {
Dialogs.profilePictureDialog(activity!!, viewModel!!).show()
}
mainMenuToolbar.setUpMainMenuToolbar(navigation!!)
root.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
viewEffect.startAlphaAnimation(userNameSmall, 0, View.INVISIBLE)
setHasOptionsMenu(true)
return root
}
private fun setUpBluetooth(): Boolean {
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
activity?.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
return true
}
private fun MainViewModel.setUpMainMenuObservers(){
//this is the original call which doesn't work
activeUser.observe(activity!!, Observer {
log("Active user id = $activeUserId") //this prints correct id
if(it == null) log("USER IS NULL")
else log("USER : ${it.name}") // and this prints that user is null, so it wasn't found
tryCatch {
binding.profilePicture.setImageBitmap(getProfilePicture(it, 256))
}
})
//this was added for testing purposes. It returns a list of all users in the db.
databaseData.getAllUsers.observe(activity!!, Observer {
log("ALL USERS:")
it.forEach{user: User ->
log("NAME : ${user.name}, ID = ${user.id}") //this prints each user with the correct name and id
}
log("Active user id = $activeUserId") //this prints correct active user id
val user = it.first { id == activeUserId } // on this line app crashes, as if 1 != 1.
log("USER : ${user.name}")
tryCatch {
binding.profilePicture.setImageBitmap(getProfilePicture(user, 256))
}
})
bluetoothData.steps.observe(activity!!, Observer {
binding.stepsTodayCounter.text = it.toString()
})
bluetoothData.location.observe(activity!!, Observer {
val text = "${lastDayData.getLastDayDistanceFormatted()} Km"
binding.distanceTodayCounter.text = text
})
bluetoothData.isBluetoothConnected.observe(activity!!, Observer {
when (it) {
true -> binding.changeOnBTConnected("Connected!", R.drawable.bt_connected_icon)
false -> binding.changeOnBTConnected("Not Connected!", R.drawable.bt_disconnected_icon)
}
})
}
private fun FragmentMainMenuBinding.changeOnBTConnected(changeText: String, changeDrawable: Int){
connectionStatus.text = changeText
mainMenuToolbar.menu?.findItem(R.id.menu_bluetooth)?.icon =
activity!!.getDrawable(changeDrawable)
Toast.makeText(activity!!, "You are $changeText!", Toast.LENGTH_LONG).show()
}
private fun Toolbar.setUpMainMenuToolbar(navigation: INavigationCallback) {
inflateMenu(R.menu.main_view_menu)
menu.findItem(R.id.menu_bluetooth).setOnMenuItemClickListener {
setUpBluetooth()
}
menu.findItem(R.id.menu_settings).setOnMenuItemClickListener {
navigation.navigateTo(R.id.action_mainMenuFragment_to_settingsFragment)
true
}
}
}
所以从评论中你可以理解它有多奇怪。因此,在测试查询中,我会在控制台中打印如下:
NAME : Slava Simonov, ID = 1
NAME : Uzi, ID = 11
Active user id = 1
Shutting down VM
FATAL EXCEPTION: main
...
我希望有人能够帮助我,因为我已经没有想法了,为什么会发生这种情况。感觉像是某种错误。如果您需要我的其他代码,我可以附上它,请随时询问。提前感谢大家。
解决方案
推荐阅读
- android - 如何解决在等级失败错误中添加 pro-guard 后生成 apk 的问题?
- python - Python readline忽略csv文件中的标题
- ios - AppCenter iOS 崩溃报告 - 无法理解导致崩溃的原因
- node.js - 我可以在地图对象中使用 if 语句来处理空值吗?
- kubernetes - apacheignite/web-console-backend 图像有一个问题“等待:CrashLoopBackOff”
- jquery-ui - 如何在使用 jQuery.UI 拖动时修复拖动元素脱离上下文问题
- java - 无法从蓝牙发送和接收任何数据
- api - Websocket ping 超时冻结了最重要的“机器人”
- python - 如果原始文件中的名称有效但我的主文件中不存在,如何包含一个条件,以使匹配列给出空白?
- android - 如何解决 Android 中的“app:transformClassesWithDesugarForDebug”?