使用 searchView 以及 ROOM 数据库和实时数据时潜在的内存泄漏

问题描述 投票:0回答:1

我希望在利用 ROOM 库的应用程序中实现 SearchView 功能。在我的在线研究过程中,我注意到许多示例都遵循类似于以下的模式:

override fun onQueryTextChange(newText: String?): Boolean {
        if (newText != null) {
            mViewModel.searchAllDatabase(newText).observe(viewLifecycleOwner){
                ...
            }
        }
        return true
    }

现在,我很想知道我是否做对了整个事情。是否可以使用这种方法,每次用户输入新字母并触发 onQueryTextChange 方法时都会创建一个新的观察者?如果是这样的话,这是否可能导致内存泄漏?或者,另一方面,viewLifecycleOwner 是否自动处理这些观察者,确保它们在不再需要时被处置?

编辑:如果我们遵循这种方法会怎样:

override fun onQueryTextChange(newText: String?): Boolean {
        if (newText != null) viewModel.searchQuery.value = newText
        return true
    }

onViewCreated 内部:

viewModel.allData.observe(viewLifecycleOwner) {
        adapter.setData(it)
    }
viewModel.searchQuery.observe(viewLifecycleOwner) { query ->
        if (viewModel.allData.value != null) {
            adapter.setData(viewModel.allData.value!!.filter { it.title.contains(query) })
        }
    }
java android kotlin android-room android-architecture-components
1个回答
0
投票

从你所展示的情况来看,这确实泄漏了观察者。对于几乎每个输入或删除的字符,内存中都会有过时的观察者,直到片段的视图被破坏。更糟糕的是,如果这些观察者来自 Room,那么每次修改数据库时,它们都会运行查询,直到被释放为止。

避免这种情况的一种方法是使用基于搜索查询的切换映射操作。 switch map 操作正是我们想要的......当有新数据时,它取消观察之前的 LiveData 并开始新的 LiveData。这是在它自己的引擎盖下完成的,因此对于外部观察者来说,它只是一个 LiveData 流。

在 ViewModel 中,类似这样:

private val searchQuery = MutableLiveData("")

val queryText: String
    get() = searchQuery.value
    set(value) { searchQuery.value = value }

val searchedData = searchQuery.switchMap { query ->
    if (query.isEmpty()) repo.allData else repo.searchAll(query)
}

现在,在您的 UI 类中,您仅在

viewModel.searchedData
中观察一次
onViewCreated()
,除了在
ViewModel.queryText
中设置
onQueryTextChange()
的新值之外什么也不做。


关于您提出的解决方案,有一些缺点。

首先,尝试直接读取 LiveData 的

value
而不是观察它确实很麻烦。在这种情况下,它保留了用户在
allData
获取第一个值集之前键入字母的可能性,使屏幕保持空白,直到用户再次键入。

其次,您手动筛选数据以自己执行搜索,这可能比让存储库执行搜索效率低。数据库针对此类事情进行了优化。

© www.soinside.com 2019 - 2024. All rights reserved.