I am trying to get the values from a DB via Room but it always returns null. It should retrieve the data from DB BalancesCat. Any help? Thanks!
This is the DAO
@Query("SELECT * FROM BalancesCat") suspend fun getAllBalances(): List<BalancesCat>
Repository
suspend fun getAllBalancesCat(): List<BalancesCat>? { var balancesCat: List<BalancesCat>? = null withContext(Dispatchers.IO){ balancesCat = balancesCatDao.getAllBalances() } return balancesCat }
ViewModel
fun getAllBalancesCat(): List<BalancesCat>? { var balancesCat: List<BalancesCat>? = null viewModelScope.launch { balancesCat = repository.getAllBalancesCat() } return balancesCat }
and the Fragment where I want to retrieve the data
balancesCatViewModel = ViewModelProvider(requireActivity(), BalancesCatViewModelFactory(requireActivity().application)). get(BalancesCatViewModel::class.java) allBalancesCat = balancesCatViewModel.getAllBalancesCat() var allBalancesCatNew: BalancesCat val currentDate1 = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) val dateCurrent1 = Date.valueOf(currentDate1) allBalancesCat?.forEach { if(it.date != dateCurrent1){ it.date = dateCurrent1 allBalancesCatNew = it balancesCatViewModel.update(allBalancesCatNew) } }
Advertisement
Answer
This isn’t your problem, but I have to mention, your repository’s getAllBalancesCat()
function is needlessly complicated and doesn’t need to return a nullable. Since balancesCatDao.getAllBalances()
is a suspend
function, it is pointless to wrap it in withContext()
. You never need to specify a context to call a suspend function (unless the suspend function was incorrectly designed and has blocking code in it). It can be simplified to:
suspend fun getAllBalancesCat(): List<BalancesCat> = balancesCatDao.getAllBalances()
Your ViewModel function is incorrect and is guaranteed to always return null. It creates the variable balancesCat
with initial value of null, launches a coroutine, and then returns the null balancesCat
before the coroutine has even started. Coroutines on the ViewModel scope are added to the main thread looper’s queue, but that puts them after the code that is currently running in the main thread, like the rest of this function.
The correct way for this ViewModel function to work is to also be a suspend function that returns a non-nullable List:
suspend fun getAllBalancesCat(): List<BalancesCat> = repository.getAllBalances()
And in your Fragment, launch a coroutine from the lifecycleScope
to do all this work that partially involves calling suspend function(s).
I can’t comment very much on the fragment code because it’s not shown in context, but I see some possible code smells. Properties that should probably just be local val
s in the function. The Fragment shouldn’t need to get values from the ViewModel and then store them in properties, and if it does, then the Fragment’s code gets more complicated because it has to check if the local property holds the up-to-date value or not, instead of just getting it from the source (the ViewModel).