Skip to content
Advertisement

Android Room Query returning null

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

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement