如何使用房间执行繁重的数据库操作?
Posted
技术标签:
【中文标题】如何使用房间执行繁重的数据库操作?【英文标题】: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 one 或 that 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】:如果房间仍然使用自定义调度程序,那么调用哪个调度程序房间查询又有什么关系?
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查询调用返回,可以使用async
launcher和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()
参考:
-
https://***.com/a/59376666/1994950
https://***.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 代码中引入的复杂性...以上是关于如何使用房间执行繁重的数据库操作?的主要内容,如果未能解决你的问题,请参考以下文章