【问题标题】:How to perform heavy database operations with room?如何使用房间执行繁重的数据库操作?
【发布时间】:2020-04-19 19:20:18
【问题描述】:

我正在使用房间数据库来运行一些繁重的数据库操作。我没有将 LiveData 用于此操作,因为我仅将结果用于计算。现在如果在我的主要片段中我有这个

override fun onActivityCreated(savedInstanceState: Bundle?) {
    lifecycleScope.launch {
        val result = viewModel.someHeavyOperation() // a suspend fun
        doSomething(result)
    }
}

我在启动时收到Skipped xx frames! Your application might be doing to much work on main thread.,如果我忽略数据库查询,我不会收到。

现在这里的一些答案,如 this onethat one 似乎建议在 IO 线程上运行查询,如

override fun onActivityCreated(savedInstanceState: Bundle?) {
    lifecycleScope.launch {
        withContext(Dispatchers.IO) {
            val result = viewModel.someHeavyOperation() // a suspend fun
        }
        doSomething(result)
    }
}

这确实提高了我的表现。让我感到困惑的是,Android 开发者在媒体上发布的 an article 中写道

注意:Room 使用自己的调度程序在后台线程上运行查询。您的代码不应使用 withContext(Dispatchers.IO) 来调用暂停房间查询。它会使代码复杂化并使您的查询运行速度变慢。

但是,他们似乎只考虑了昂贵的位是随后的计算的情况,他们似乎提出了类似的建议

override fun onActivityCreated(savedInstanceState: Bundle?) {
    lifecycleScope.launch {
        val result = viewModel.someOperation() // a suspend fun
        withContext(Dispatchers.Default) {
            doSomethingHeavy(result)
        }
    }
}

现在我的问题是:

  1. 如果房间仍然使用自定义调度程序,那么调用哪个调度程序房间查询又有什么关系?
  2. 如何在不阻塞主线程的情况下执行昂贵的房间查询?

【问题讨论】:

    标签: android kotlin android-room


    【解决方案1】:

    如果房间仍然使用自定义调度程序,那么调用哪个调度程序房间查询又有什么关系?

    Room 从2.1 版本开始引入了Kotlin Coroutine 支持。早些时候,他们不支持Coroutine。所以,首先,从build.gradle文件确定你的房间版本是否为2.1或以上:

    implementation "androidx.room:room-coroutines:${versions.room}"
    

    如果您使用的Room 版本早于2.1,则Room 将在调用者线程上执行操作。这意味着如果我们在 MAIN 线程上对 Room 进行查询调用,它将在 MAIN 上执行操作。如果我们在 IO - background 线程上调用 Room,它将在 background 上执行。

    如何在不阻塞主线程的情况下执行昂贵的房间查询?

    为此,我们应该在 IO 线程上调用 Room 查询。你已经在做正确的事情了

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {
                val result = viewModel.someHeavyOperation() // a suspend fun
            }
            doSomething(result)
        }
    }
    

    除此之外,如果需要添加等待Room查询调用返回,可以使用asynclauncher和await()方法

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        lifecycleScope.launch {
        val content = async(Dispatchers.IO) {
            viewModel.someHeavyOperation() // a suspend fun
        }
        // Using below line, we are introducing waiting for completion of someHeavyOperation() on IO thread
        // If we return any result from someHeavyOperation(), it can be accessed in result variable as below
        var result = content.await() 
        }
       }
    }
    

    参考:

    1. https://stackoverflow.com/a/59376666/1994950
    2. https://stackoverflow.com/a/59408634/1994950

    【讨论】:

    • 那么为什么medium article 说我们不应该从 IO 线程调用房间查询?
    • 我在我的问题中引用了它:“注意:房间使用自己的调度程序在后台线程上运行查询。您的代码不应使用 withContext(Dispatchers.IO) 来调用暂停房间查询。它将使代码复杂化并使查询运行速度变慢。”
    • 好的,正如我所提到的,在 Room 版本 2.1 之后,建议不要使用开发者方面的 IO 线程,因为 Room 正在为我们做这件事。但是,如果我们的遗留代码使用的是2.1以下的Room版本,则需要开发者处理。
    • 这是建议,而不是规则。我们仍然可以使用IO 作为2.1 版本的Room 的良好实践
    • 感谢您澄清这一点。我使用版本2.2.3,但我的代码使用Dispatchers.IO 运行得更快。我认为这是因为 ViewModel/Repository 代码中引入的复杂性...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    相关资源
    最近更新 更多