【问题标题】:Android - Kotlin Coroutines for handling IllegalStateException: Cannot access database on the main threadAndroid - 用于处理 IllegalStateException 的 Kotlin 协程:无法访问主线程上的数据库
【发布时间】:2021-02-21 15:00:25
【问题描述】:

在我的 Android 应用程序中,我使用 Room 作为本地数据库来存储用户的帐户信息。当我发出一个简单的Room 请求以检索存储在数据库中的Account 对象时,我收到以下错误消息:

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

这里是我发出本地数据库请求的Fragment 代码:

// AccountInformationFragment.kt


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

在ViewModel 类中,我实现了retrieveAccountData(),如下所示:

    // 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
    }

在Repository 类中,我已经像这样实现了retrieveAccountData():

// AccountRepository.kt

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

我知道我必须使用某种异步操作,因为本地数据库操作在主线程上执行时可能需要很长时间。 但是在ViewModel 类中,我在viewModelScope 中启动了协程。这还不够吗?根据异常,似乎没有。那么,有没有人可以告诉我如何正确地做到这一点。

编辑:

这是道类:

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

提前致谢

【问题讨论】:

  • 你的retrieveAccountData是挂起的方法吗?如果不是,为什么不呢?这就是自动将数据库访问跳转到后台线程的原因。
  • 我已经从 AccountDao 类中添加了 retrieveAccountData()。你的意思是我只需要添加suspend关键字?
  • @abdullahcelik 是的,尝试将suspend 添加到您正在使用的repository 和dao 中的方法中。

标签: android android-room kotlin-coroutines illegalstateexception


【解决方案1】:

根据Room documentation,如果您希望 Room 自动移动到后台线程来运行您的@Query,您可以将您的方法设为suspend 方法:

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

【讨论】:

  • 谢谢。基本上,我只是忘记了暂停关键字。现在,我明白了。
【解决方案2】:

RoomDB 支持 LiveData。您可以将查询结果作为 livedata 返回,默认情况下在后台线程中执行操作并在您的 UI 层中观察它。我已经修改了您在下面的查询,它将返回 LiveData 而不是 Account。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多