Android SQLite 快速获取游标中的所有数据

标签 android database performance sqlite cursor

我正在处理我的一个应用程序中的性能问题。也许你们中的一个人可以帮助我?!

我有一个大约有 10k 条目的数据库。 我使用 SQLiteDatabase 中的默认查询方法查询元素-类(class)。 查询本身足够快。

查询完成后,我必须在 Google map 上显示结果。 为此,我从游标生成一个结果数组,其中包含标记信息。

我使用的方法看起来有点像这样:

    final ArrayList< MarkerElement > result = new ArrayList< MarkerElement >();
    cursor.moveToFirst();
    while ( !cursor.isAfterLast() ) {
        result.add( new MarkerElement(
                cursor.getString( COL_TITLE ),
                cursor.getString( COL_SNIPPET ),
                new LatLng(
                        cursor.getDouble( COL_LAT ),
                        cursor.getDouble( COL_LNG ) ),
                cursor.getString( COL_OTHER_USEFUL_DATA ) );
        cursor.moveToNext();
    }
    cursor.close();

其中MarkerElement只是一个类,用于保存 Google map 上标记所需的值。

现在的问题是,循环遍历所有游标元素需要很长时间。 另外,我想不出像在 ListView 中那样延迟加载结果的智能方法,因为我需要同时显示所有结果。

我可以做些什么来显着加快这个过程吗?

非常感谢任何帮助!

致以诚挚的问候

最佳答案

我不太确定查询是否真的像您想象的那么快。最有可能的是,实际查询仅使用cursor.moveToFirst()语句执行,而不是在调用query()或rawQuery()(或您正在使用的任何其他查询方法)时执行。

无论如何,查询应该足够快,以使用户只需要短暂等待。如果没有,那么您可能需要考虑使用 SELECT * FROM your_table LIMIT START, COUNT 分块加载它(例如 SELECT * FROM your_table LIMIT 0, 1000 检索前 1000 行)。

查询不能在 ui 线程上发生,因此您希望在 AsyncTaskLoader 或更好的 CursorLoader 中运行它。没有 ContentProvider 的 CursorLoader 是可能的,您可以在此处看到:https://stackoverflow.com/a/7422343/534471 .

假设您需要对每个 1000 条记录运行 10 个查询,那么您将拥有 10 个可以使用 LoaderManager 进行管理的 CursorLoader。 LoaderManager 管理光标(打开和关闭它们),在方向变化时保留光标并在后台任务中运行所有内容,因此不会出现阻塞 ui 线程的问题。如果内容发生更改,LoaderManager 还会重新查询数据库(请参阅: https://stackoverflow.com/a/5603959/534471 )。 当 LoaderManager 通知您的 fragment 或 Activity 光标已完成加载时,它将调用 onLoadFinished() (请参阅: http://developer.android.com/reference/android/support/v4/app/LoaderManager.LoaderCallbacks.html )。

减慢代码速度的不仅仅是查询数据库,还创建了 10'000 个 MarkerElement 和另外 10'000 个 LatLng 对象。我不知道您的要求,但如果您发现有机会在没有这些对象的情况下工作,那肯定会加快您的代码速度。消除 MarkerElements/LatLng 的另一个理想效果是内存使用。对于面向手机的应用程序来说,20'000 个包含 3 个 String 和 2 个 Double 的对象是相当可观的。

使用 CursorLoaders 和 LoaderManager 将允许您从光标检索值并直接填充您的 ui View ,而无需 MarkerElements 和 LatLng。它还允许您延迟加载。每当为 CursorLoader 之一调用 onLoadFinished() 时(除非从非 ui 线程调用 initLoader/restartLoader,否则在 ui 线程上调用 onLoadFinished()),您都可以填充 View 。如果一次填充 1000 个 View 太多,则可以将查询分解为更小的部分,或者添加一种机制以 10 或 100 秒的 block (对于每个游标)填充 View 。

如果您需要当前存储在 MarkerElement 中的信息,例如当用户选择标记之一时,在显示标记的 View 上使用 setTag() 来存储数据库记录的主键。使用该键可以从数据库中检索记录,甚至可以从已查询的游标中检索记录(这将需要一些映射机制,但这是可行的)。

摘要:

  • 将查询拆分为多个子查询以检索较小的数据集
  • 使用 CursorLoaders 和 CursorManager 管理不同的查询/游标
  • 不要为每行创建 MarkerElement 和 LatLng,而是直接从返回的游标填充 View
  • 可能需要分几步对每个光标进行填充,以保持用户界面的响应能力
  • 在 View 上使用 setTag() 以便能够检索 View 背后的数据

关于Android SQLite 快速获取游标中的所有数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16125919/

相关文章:

sql - 通过数据库中的文本字段实现智能搜索

sql-server - 如何过滤 WHERE 子句中的 TOP 1 条件

android - OpenSSL Android NDK 的包装类

java - EditTextPreference 不适用于字符串

php - 投票按钮的数据库设计

c# - Excel Interop - 效率和性能

php - PHP中 "include"的性能成本是多少?

android - 来自另一个 Activity 的 StopService 不起作用?

java - 我们需要在哪个 fragment 方法中消费长期的weservice

android - 有人可以解释 SQLiteOpenHelper getType