abdullah celik
abdullah celik

Reputation: 551

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

Upvotes: 2

Views: 708

Answers (2)

Anand
Anand

Reputation: 57

RoomDB supports LiveData. You could return the query result as a livedata which is by default does the operation in the background thread and observe it in your UI layer. I have modified your query below which will return LiveData instead of Account.

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

Upvotes: 1

ianhanniballake
ianhanniballake

Reputation: 200120

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

Upvotes: 6

Related Questions