【问题标题】:Multiple ListAdapters or a single one, using filtering (Android Performance)多个 ListAdapter 或单个,使用过滤(Android 性能)
【发布时间】:2011-12-04 20:44:30
【问题描述】:

尝试关注关于列表的一般“注意事项”,例如是 添加和删​​除 200 项列表中的 30 项比清除更好 并重新填充?或者这方面的任何其他提示 - 我真的不能尝试 在我的手机上,为此禁食:-)

有什么方法可以计算列表操作的内存开销/计算能力。背景如下:

我在页面上有一个列表视图,该页面有例如底部的 3 个选项卡(全部、搜索、最近)。现在,如果您单击一个选项卡,列表视图应该会向您显示适当的项目。

现在有两种不同的方法,一种是:

使用单个 ListAdapter,相应地过滤项目
- 如果单击全部,只需将数据库中的所有项目都放入其中
- 如果你点击最近,只要把符合要求的项目放上去

使用两(三个..)ListAdapters,每个类别一个
- 如果单击全部,则将列表的 setAdapter() 设置为适当的一个
- 如果你点击最近,setAdapter() 到合适的一个

我们谈论的是一个包含 200 个项目的列表,它们是从数据库中创建的复杂对象。当例如搜索一个项目,你输入部分标题,列表应该只显示适当的项目。这些项目不会被重新创建,我只会查询 ID,并使用缓冲的项目(请参阅后面的数据结构)。

我也不确定“在哪里过滤”,我可以在数据库中进行(从 where title LIKE abc 中选择),然后是:

  • 从列表中删除不匹配项并添加所有匹配(但不包括)项
  • 清除整个列表,添加所有匹配

再次澄清App数据的结构:

  • 数据库包含原始的简单条目(带有 ID + 标题 + ...)
  • HashSet 具有复杂的条目,从数据库创建一次,只读 + 总是所有条目
  • ArrayList 显示在 listView 中的当前条目

我希望你明白我的意思,我正在尝试感受一下“昂贵”的操作。也许,作为回答的最后动力,我会写一些案例,您可以就它们的成本发表意见:

  1. 从带有“title LIKE”的 DB 中选择 N 个项目(仅限 ID)
  2. 使用“title.contains()”迭代包含 200 个项目的列表并仅使用匹配项
  3. 从列表视图显示的数组列表中删除 100 个项目
  4. 从未显示的数组列表中删除 100 个项目,然后连接并显示

感谢您提供任何反馈或任何有关不良做法的提示。通过处理可见列表元素,而不是先“在后台”执行,然后设置新的 ListAdapter,尤其是可能的事件触发问题

【问题讨论】:

  • 来自 cmets,我认为最好更改您接受的答案

标签: android performance android-listview


【解决方案1】:

我看到你已经接受了一个答案,但我认为我不同意,因为ArrayList 必须复制所有元素,如果中间是添加或删除的元素。

我了解到您已经拥有包含所有条目的 HashSet

在这种情况下,我相信最有效的适配器是自定义 ListAdapter,灵感来自 ArrayAdapter

  • 您的适配器存储所有条目的ArrayList mAllObjects(用于“全部”选项卡)。
  • 您的适配器存储最近条目的ArrayList mRecentObject(用于“最近”选项卡)
  • 您的适配器存储匹配条目的ArrayList mMatchObject(用于“搜索”选项卡)
  • 您的适配器有两个过滤器
    • 最近的过滤器返回 mRecentObject 列表(如果它不存在则创建它)
    • 匹配过滤器创建一个新的mMatchObject 列表并添加匹配元素。此处无需进行优化。 ArrayList 上的delete()方法是 O(n)。

【讨论】:

  • 我是否理解正确,在“简单的语音”中,最好清除 ArrayList 并再次填充 HashSet 中的值,而不是一一删除 20 个项目(可能导致20 次复制动作)- 我不确定你最后一句是什么意思。而且你的答案肯定比另一个更好:-)
  • @Christian 最后一句解释:当你做delete()ArrayList中的第一项时,有199个对象被移动(第2到第1,第3到第2等)。当您删除第 n 个元素时,有 N-n 个操作。一次删除需要 O(N) 次操作。如果你添加一个元素,同样的复杂性。
  • @Christian 是的,如果你 deleteAll 并且只添加匹配的元素,arraylist 会更快(我会从 mAllObjects 匹配它们,但你也可以查询数据库,然后查找相应的HashSet 中的条目)。
  • 我在这里同意@rds。我没有充分考虑您对视图中记录的支持实施。清除 ArrayList 并根据需要添加对象将比从 ArrayList 中删除许多内容更快。
【解决方案2】:

我不确定我是否理解您要对整个列表执行的操作,但是关于 filtering,您应该在数据库端执行此操作(在您提到的 select 语句中)...尤其是因为此应用程序适用于移动设备(鉴于顶部的评论),您希望将密集操作卸载到服务器端,而不是将它们留在移动设备上。

【讨论】:

  • 这里有两个问题。首先,我正在使用 SQlite DB,所以 db 在电话上(它可能仍然比处理列表更快)。第二个是复杂对象的问题。它们已经存在,所以我正在数据库中进行搜索(例如 WHERE name LIKE),获取 ID,然后我需要使用这些 ID 来“过滤”或“创建”结果列表(来自复杂的 HashSet对象由它们的 ID 存储)-希望这是可以理解的 :-)
【解决方案3】:

在黑暗中轻微刺伤。从(相当粗略的)"Designing for Performance" document 看来,对象创建,尤其是短暂的对象创建,成本非常高。我会将此解释为来自两个地方:1)对象创建开销(尤其是对于复杂对象),以及 2)当这些对象超出范围或被显式销毁时调用 GC。

因此,作为起点,我认为您希望在数据库中完成工作,并将增量推送到视图中。因此,根据您最初的问题,请执行以下操作:

  • 从列表中删除不匹配的项目并添加所有匹配(但不包括)的项目

我想您可以为此编写一个综合基准测试来感受速度上的差异。但是,在我自己的代码中,我尽量避免使用性能文档所建议的短期对象。 GC 的影响是巨大的,因为它经常会干扰 UI 线程并使其在工作时打嗝。

【讨论】:

  • 谢谢,这很适合我的架构。我实际上是逐渐创建“大对象”(需要时详细说明)并让它们永远活着——之后只查询 ID 并获取对象。如果我发现更多细节,我会更新这篇文章。现在让我们称之为回答:-)
  • 删除不匹配的元素意味着复制元素后面的所有元素。这远非最佳。
  • 这条评论就是我要找的。因此,清除列表并从 HashSet 添加所有(例如 150 个)匹配项应该比从列表中删除 50 个(共 200 个)项更快。
  • 我的推理听起来不对。没有对象创建,在“从列表中删除不匹配的项目并添加所有匹配(但不包括)的项目”,但在“清除整个列表,添加所有匹配的项目”中也没有。但是,底层数组中有更多对象的比较和移动。
  • 我认为@rds 试图提出的观点很好。如果您的 List 实现是 ArrayList,则删除和插入不是 O(1)。底层结构是一个数组,所以迭代很快,但删除不是,因为当你删除第 n 个项目时,你必须打乱所有 n+1 个项目。您可能会考虑使用LinkedList,它具有更好的插入/删除性能,但随机访问性能更差。检查this
猜你喜欢
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 2021-03-28
  • 1970-01-01
  • 2020-12-10
  • 1970-01-01
  • 1970-01-01
  • 2015-03-11
相关资源
最近更新 更多