android – RoomDb Query Returning null-ThrowExceptions

Exception or error:

I am querying my room database to check if an item exists, however the query always returns null even though the item is already in the DB. I am using coroutines

This is my query

@Query("SELECT EXISTS(SELECT * FROM cart_item WHERE productId = :productId)")
    suspend fun getItemCount(productId: Int): Int?

The function in my repository

 suspend fun getCartItemCount(productId: Int): Int? {
        return coroutineScope{
            cartItemDao.getItemCount(productId)
        }
    }

In my view model

fun getCartItemCount(productId: Int): MutableLiveData<Int>? {
        var itemCount: MutableLiveData<Int>? = MutableLiveData()
        launch {
            itemCount!!.value = repository.getCartItemCount(productId)
        }

        return itemCount
    }

And this is how i implement it in my Fragment

   fun getCartItemCount(productId: Int){
        var itemCount: Int? = null

       mainViewModel!!.getCartItemCount(productId)!!.observe(viewLifecycleOwner, Observer {
           itemCount = it
       })
        Log.d("ITEMCOUNT ----> ", " $itemCount")
    }
How to solve:

I think you are missing some fundamentals on how to use coroutines.

  1. Your database query is a suspend method that will execute and “suspend” tge execution until it returns.
  2. Since your repository function is still suspend, you can live it up to the user on which scope to run.
  3. Then we have the LiveData issue, you log the itemCount while still null. The trigger never did, and even if it does, it won’t execute your log statement.
  4. Your view model uses LiveData to post changes, then we do you need to return a value on your method?

    • Actual problem lies in waiting for the result synchronously, which is not.

Suggested Changes

Repository

// repository
suspend fun getCartItemCount(productId: Int): Int? {
   return cartItemDao.getItemCount(productId)

}

View Model

var itemCount: MutableLiveData<Int> = MutableLiveData()

// maybe rename method as it's not a getter anymore
fun getCartItemCount(productId: Int) {
  viewModelScope {
    itemCount.value = repository.getCartItemCount(productId)
  }
}

In your fragment

fun getCartItemCount(productId: Int){
  mainViewModel?.observe(viewLifecycleOwner, Observer {
    itemCount = it
    // this will be triggered every time the "LiveData.value" changes
    // this could return null if the live data value is not set.
    Log.d("ITEMCOUNT", "$it")
  })
  mainViewModel?.getCartItemCount(productId)
}

Suggested Reading:

Leave a Reply

Your email address will not be published. Required fields are marked *