Search code examples
androidandroid-roomkotlin-coroutinesillegalstateexception

Android - Kotlin Coroutines for handling IllegalStateException: Cannot access database on the main thread


In my Android App, I use Room as local database to store the Account information of a user. When I make a simple Room request to retrieve the Account object stored in the database, I get the following error message :

java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

Here, is the Fragment code from which I make the local database request:

// AccountInformationFragment.kt


accountDataFragmentViewModel.retrieveAccountData(accountId).observe(viewLifecycleOwner, Observer {
       // do some stuff
    })

In the ViewModel class I have implemented retrieveAccountData() like this:

    // AccountInformationFragmentViewModel.kt        

    // used to get the account from the local datasource
    fun retrieveAccountData(id:Long): LiveData<Account>{
        val result = MutableLiveData<Account>()
        viewModelScope.launch {
            val account = authRepository.retrieveAccountData(id)
            result.postValue(account) 
        }
        return result
    }

In the Repository class, I have implemented retrieveAccountData() like this:

// AccountRepository.kt

suspend fun retrieveAccountData(accId:Long): Account =
        accountDao.retrieveAccountData(accId)

I understand that I have to use some sort of asnyc operation because the local database operation may take a long time when its performed on the main thread. But in the ViewModel class I launched the coroutine inside the viewModelScope. Is that not enough? Based on the exception, it seems not. So, is there someone who could tell me how to do this correctly.

EDIT:

Here is the Dao class :

@Query("SELECT * FROM account_table WHERE id = :id")
fun retrieveAccountData(id: Long) : Account

Thanks in advance


Solution

  • As per the Room documentation, if you want Room to automatically move to a background thread to run your @Query, you can make your method a suspend method:

    @Query("SELECT * FROM account_table WHERE id = :id")
    suspend fun retrieveAccountData(id: Long) : Account