【问题标题】:ListView: filtering via Filterable vs. restarting CursorLoader with new URIListView:通过 Filterable 过滤与使用新 URI 重新启动 CursorLoader
【发布时间】:2013-08-09 10:14:32
【问题描述】:
ListView 实现了过滤内容的方法。你能详细说明什么时候应该使用它吗?
据我了解,这种过滤适用于基于数组的适配器——所有数据已经在内存中。这样,过滤器只会帮助跳过不应显示的数据。
但是,如果ListView 与游标适配器(SQLite 数据库)一起使用以显示大量项目,则数据可能不在内存中。另一方面,过滤值可以嵌入到SQL查询中,有效地得到缩减后的数据集。
ListView 的过滤机制是否也设计用于基于游标的数据?什么时候应该使用 Filterable 以及什么时候应该在不使用 ListView 过滤器的情况下将过滤器传递给 SQL 查询?什么时候应该使用这种或那种方法,有什么建议吗?
谢谢
附:该问题与之前结合了两者的How the system of URIs should be designed? 分开。
【问题讨论】:
标签:
android
android-listview
android-cursoradapter
【解决方案1】:
您可以同时享受两者的好处。设置Filter 但在FilterQueryProvider 的runQuery() 中,不要对数据库运行全新的查询。只需在原始光标周围使用包装器即可过滤掉不需要的内容。这个包装器的创建相当简单,在 SO 上也是 mentioned。
根据最近的经验:不要同时使用两者。 Filterable 做自己的后台处理,所以如果你使用它,根本不需要任何CursorLoader。实际上,同时使用两者并没有真正的危害,但会导致不必要的查询和性能下降。您的runQuery() 查询应该处理两种情况,未过滤(约束为空)和过滤(约束不为空),这意味着所有查询操作都通过过滤器并且仅通过过滤器运行。启动它所需要做的就是在适配器的构造函数中调用它:
setFilterQueryProvider(this);
getFilter().filter(null);
还有一个让我有些头疼的意外惊喜。 CusorLoader 很好地管理光标,即使在严格模式下也没有问题,但使用Filterable,情况不太完美。正常操作没有问题,它确实处理了旧的游标,但活动生命周期的变化可以抓住它。我找到的解决方案是扩展与这些适配器一起使用的 ListView/RecyclerView 视图,并确保最终销毁光标:
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
((CursorAdapter) getAdapter()).changeCursor(null);
}
作为替代方案,如果您不想扩展,您可以从您的活动的 onDestroy() 为每个适配器支持的视图调用相同的方法,但我更喜欢设置它并忘记它的方法第一个优惠。
【解决方案2】:
ListView 的过滤机制是否也是为光标设计的
基于数据?
通过Filter 类的过滤机制是为适配器实现的(与适配器有关的逻辑操作),ListView 只是该适配器的简单用户。
什么时候应该使用 Filterable 以及什么时候应该将过滤器传递给
不使用 ListView 过滤器的 SQL 查询?有没有
什么时候应该使用这种或那种方法的建议?
我认为没有关于使用哪一个的建议(或者我自己没有看到它们)。 Filter 类是专门为优化过滤过程而设计的(例如,如果初始过滤操作需要一些时间并且用户在这段时间内提出了其他请求,那么Filter 类将只执行最后一次计划的过滤操作(另一个没有意义))。令我感到羞耻的是,我不知道CursorLoader 是否会在那个时候调用onLoaderReset() 回调时取消加载,如果它不这样做会很糟糕,因为你会做所有这些(如果用户在 abcd 之后快速进行过滤,你就不想做 a b c d,你想做 a d)。您可以对其进行优化,但与过滤器相比的麻烦是没有意义的。
但是,如果 ListView 与游标适配器(SQLite
数据库)用于显示很多项目,数据可能不在内存中。
另一方面,过滤器值可以嵌入到 SQL 查询中以
有效地得到缩减后的数据集。
测量东西。进行具有更大约束的新查询将减少数据集,但代价是用户看到结果的速度较慢。如果时间不可接受,则进行单个查询(对于初始约束)然后过滤该数据集而不需要额外的 sqlite 查询可能会更有意义。