'android room query method returning list but is wrongfully treated as LiveData

I have a DAO where I'm querying objects, some as liveData and most as regular functions. But today I am stuck in a loop of errors. If I access the object in main thread, it gives error of Cannot access database on the main thread since it may potentially lock the UI for a long period of time. But when used on a IO thread it gives another error of: can not add observer without main thread. The second error is weird because it should not be an observer but a simple list object from query.

DAO code:

@Dao
interface ItemsDAO {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    ...

    @Delete
    ...

    @Query("SELECT * FROM table_items ORDER BY timestamp")
    fun getAllItems(): LiveData<List<Item>>

    @Query("SELECT * FROM table_items")
    fun allItemsList(): List<Item>

}

on repository:

fun getAllItems() =  ItemsDAO.getAllItems()
fun allItemsList() = ItemsDAO.allItemsList()

ViewModel:

val getItems = itemPoolRepository.getAllItems()
val allItemsList  = itemPoolRepository.allItemsList()
//also checked same result with the following:
//fun allPoolsItemsList()  = itemPoolRepository.allItemsList() // Gives error : Method addObserver must be called on the main thread

Fragment:

    val itemsList = itemsViewModel.allItemsList // the error occurrs here
    //val itemsList = itemsViewModel.allItemsList()

If it is in main thread I get, java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. If in IO thread, I get : java.lang.IllegalStateException: Method addObserver must be called on the main thread.

It is a simle list, why it is treated as observer? I have other similar methods to access the queried list similar way with method parameters and those works fine on a IO thread. Can anyone tell me any solution just to access the list on any thread?

Update. I have added suspend but that did not solve anything and it still thinks I am adding observer.

@Query("SELECT * FROM table_items")
suspend fun allItemsList(): List<Item>


Solution 1:[1]

Are you using Coroutine? the methods inside DAO & repository should be suspend fun, then you can set the thread by using CoroutineScope.

Solution 2:[2]

For Cannot access database on the main thread -> use suspended functions and coroutines and since fragment is accessing viewModel through di I assume. and viewmodel is created lazily upon access, and creation of the viewmodel must be done on the main thread. Simply trying to access the viewmodel on the main thread before accessing its functions solves the problem. so,

// Access viewmodel so that it gets initialized on the main thread
itemsViewModel
val list = itemsViewModel.getList()

Solution 3:[3]

Even if you just want the list, database needs to perform the operation on separate worker thread. You could use the same approach as you done for

@Query("SELECT * FROM table_items ORDER BY timestamp")
fun getAllItems(): LiveData<List<Item>>

Just replace

@Query("SELECT * FROM table_items")
fun allItemsList(): List<Item>

with

 @Query("SELECT * FROM table_items")
 fun allItemsList(): LiveData<List<Item>>

Whenever we are wrapping returned value into an observable, Room Database ensure that the query is run on background thread.

Now in Fragment, add observable to look for latest changes

    // The onChanged() method fires when the observed data changes and the activity is
    // in the foreground.
    itemsViewModel.allItemsList.observe(owner = viewLifecycleOwner) { items ->
        // Do something with the data.
      
    }

Solution 4:[4]

Here how i have managed to get list

In My Dao

@Query("SELECT * FROM table_items")
suspend fun allItemsList(): List<Item>

In My RepoImpl

suspend fun allItemsList(): List<Item> {
    return itemDao.allItemsList()
}

In My ViewModel

suspend fun getItemList(): List<Item> {
    return itemRepo.getItemList()
}

In My Activity

lifecycleScope.launch {
    val items = viewModel.getItemList()
    //Do Whatever with data
}

Code From My Running Project with your usecase

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 feigo808
Solution 2
Solution 3 Hussain
Solution 4 gulab patel