当前位置: 首页 > 知识库问答 >
问题:

如何在有空间的情况下执行繁重的数据库操作?

贺靖
2023-03-14

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

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

我得到一个跳过xx帧!您的应用程序在启动时可能会在主线程上做很多工作。如果忽略数据库查询,就不会得到这些工作。

这里的一些答案(比如这个或那个)似乎建议在IO线程上运行查询,比如

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

注意:Room使用自己的dispatcher在后台线程上运行查询。您的代码不应该使用withContext(Dispatchers.io)来调用挂起房间查询。这将使代码复杂化,并使您的查询运行得更慢。

然而,他们似乎只考虑了这样的情况,即昂贵的位是随后的计算,在那里他们似乎建议了类似于

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

现在我的问题是:

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

共有1个答案

杨骁
2023-03-14

如果room使用自定义调度器,那么从哪个调度器调用room查询有什么关系呢?

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

除此之外,如果需要添加等待直到房间查询调用返回,可以使用Async启动器和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() 
    }
   }
}

参考:

    null
 类似资料:
  • 我想为android构建一个计算器应用程序,为此我需要一个解析器来转换要求解的字符串表达式。现在Java和Kotlin不支持eval函数,仅仅为了一个操作而导入javascript引擎可能会让我面临各种漏洞。所以我做了自己的计算器解析器。现在它工作得很好,除了crash中的负数外,所有算术运算都工作得很好。我确实知道问题是什么,因为我使用数学符号分隔字符串,但我不能在负值中执行任何操作。 输入:-

  • null 我看到过其他答案,提到了一个名为UCANAccess的Access数据库的JDBC驱动程序。如何设置Java项目以使用这种方法? (建议从Java使用Access数据库的更好方法的答案也是最受欢迎的。)

  • 问题内容: 我有一个使用JAXB创建的相当大的重复XML。将整个对象存储在内存中然后进行封送处理会占用太多内存。本质上,我的XML如下所示: 目前,我对这个问题的解决方案是将根标记“硬编码”到输出流,并逐个编组每个重复元素: JAXB以某种方式生成这样的XML 尽管这是一个有效的XML,但它看起来很难看,所以我想知道是否有任何方法告诉编组不要为item元素放置名称空间?还是有更好的方法使用JAXB

  • 问题内容: 我想在Centos7上使用shell脚本自动生成一对ssh密钥,我已经尝试过 所有这些命令都不起作用,仅输入一个“ enter”,然后在“ Enter passphrase(空无密码)为空”时停止shell脚本,我只想知道如何在shell中连续模拟多个“ enter”。 非常感谢任何人的帮助! 问题答案: 只需 使用一个空白通 使用标志: 要覆盖密钥文件 (在此示例中): 从 手册 页

  • 我有一个动作执行,其中一个if/fe是如果用户按“A”键,它会将文本设置为不同的内容。程序不是在按“A”后设置文本,而是跳过设置文本并向下移动到下面的if语句。我的问题是,如何让我的程序在我的if语句之前设置文本?我的代码在下面,谢谢!