【问题标题】:Android SQLite get all data from cursor fastAndroid SQLite 快速从游标中获取所有数据
【发布时间】:2013-04-20 22:39:46
【问题描述】:

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

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

查询完成后,我必须在 Google 地图上显示结果。 为此,我从包含标记信息的光标生成一个结果数组。

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

    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 地图上标记所需的值。

现在的问题是,遍历所有游标元素需要很长时间。 我也想不出一种聪明的方法来像在 ListView 中那样延迟加载结果,因为我需要同时显示所有结果。

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

非常感谢任何帮助!

最好的问候

【问题讨论】:

    标签: android database performance sqlite cursor


    【解决方案1】:

    我不太确定查询是否真的像你想象的那么快。实际查询很可能仅使用 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 个字符串和 2 个 Double 是相当可观的。

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

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

    总结:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-07
      相关资源
      最近更新 更多