Запрос Android Room getById (id: Int) возвращает действительный объект при вызове из первого фрагмента, но возвращает ноль при вызове из всех остальных - PullRequest
0 голосов
/ 01 марта 2019

Я работаю над школьным проектом, и у меня началось странное поведение в комнате.Я должен признать, что все раньше работало корректно , но после изменения некоторых вещей он остановился, и теперь он не работает, хотя я вернул почти все туда, где он был.

Вот мой 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 , место, где тот же запрос, что и выше, возвращает ноль.Я также попытался проверить это, поэтому прочитайте комментарии, чтобы лучше понять, что я сделал:

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
 ...

Я надеюсь, что кто-нибудь сможет мне помочь, потому что у меня закончились идеи, почему это могло произойти.Это похоже на какую-то ошибку.Если вам нужны другие части моего кода, я могу прикрепить его, просто не стесняйтесь спрашивать.Спасибо всем заранее.

...