【问题标题】:Room allowMainThreadQueries with Kotlin coroutines房间 allowMainThreadQueries 与 Kotlin 协程
【发布时间】:2019-06-28 02:25:25
【问题描述】:

Android 官方文档指出不推荐使用allowMainThreadQueries(),因为它可能会长时间锁定 UI 并触发 ANR。 但是 Kotlin 协程让我们可以在主线程中执行一些操作,而不会有效地阻塞 UI。

所以我要问:使用allowMainThreadQueries() 并在主线程上运行的 couroutine 范围内访问数据库是否安全?如下所示:

// WITH allowMainThreadQueries()
val activityJob = Job()
val mainScope = CoroutineScope(Dispatchers.Main + activityJob)
mainscope.launch {

    // access room database and retrieve some data

    // update UI with data retrived

}

或者我们应该坚持不允许主线程查询并在另一个线程中执行数据库查询的旧方式?

// WITHOUT allowMainThreadQueries()
val activityJob = Job()
val defaultScope = CoroutineScope(Dispatchers.Default + activityJob)
val mainScope = CoroutineScope(Dispatchers.Main + activityJob)
defaultScope.launch {

    // access room database and retrieve some data

    mainScope.launch {
        // update UI with data retrived
    }

}

我问是因为前一种方式(allowMainThreadQueries()):

  • 更具可读性(我可以在访问数据库的函数的相同协程上下文中更新 UI,而无需在另一个协程范围内启动 UI 更新)
  • 允许更简单的错误处理
  • 只使用一个协程作用域(因此需要关心的作用域更少)

【问题讨论】:

  • 如果数据库访问方法标记为suspend,那么您可以使用第一种方法,否则第二种方法。

标签: android kotlin android-room kotlinx.coroutines


【解决方案1】:

你不应该需要allowMainThreadQueries() 才能工作。作用域协程在其线程中执行。

这是我不久前做的:

@UiThread
fun getUsers(context: Context): LiveData<List<User>> {
    if (!::users.isInitialized) {
        users = MutableLiveData()
        users.postValue(MyDatabase.get(context).users().getAll())
        GlobalScope.launch(Dispatchers.Main) {
            val usersFromDb: List<User> = async(Dispatchers.IO) {
                return@async MyDatabase.get(context).users().getAll()
            }.await()
            users.value = usersFromDb
        }
    }
    return users
}

您可以看到这个getUsers() 方法从主线程调用,返回一个LiveData(在这种情况下很方便)。数据库查询发生在GlobalScope.launch()

所以是的,你的设计是我个人喜欢的。一个有效的。但我认为你根本不需要allowMainThreadQueries()。欢迎阅读(我的)博文:https://proandroiddev.com/android-viewmodel-livedata-coroutines-contraption-e1e44af690a6

【讨论】:

  • 我需要 allowMainThreadQueries() 否则会出现运行时错误,我没有使用 MutableLiveData,只是通过 Dao 访问数据库实体
  • 在 CoroutineScope 中,您不需要 allowMainThreadQueries() 并且不会收到任何异常,这就是我的观点。这就是我正在使用的代码。没有allowMainThreadQueries()
  • 不建议使用全局范围,除非您在工作后明确取消
【解决方案2】:

建议在viewmodelScope里面访问你的ViewModel中的数据库。 如果您需要从活动或片段使用访问房间数据库

lifecyclescope.launch{ // access database dao functions here which are suspend in definition. }

或者在生命周期范围内使用 withContext(Dispatchers.IO){}

更改您的线程

【讨论】:

    猜你喜欢
    • 2021-12-17
    • 2020-01-04
    • 2019-08-19
    • 1970-01-01
    • 2019-09-30
    • 2019-07-17
    • 2019-06-22
    • 2020-04-12
    • 2020-08-29
    相关资源
    最近更新 更多