Android SQLite快速从光标获取所有数据

grA*_*uit 2 database sqlite performance android cursor

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

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

查询完成后,我必须在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();
Run Code Online (Sandbox Code Playgroud)

其中MarkerElement只是包含所需的值在谷歌地图标记的类.

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

我有什么办法可以大大加快这个过程吗?

任何帮助是极大的赞赏!

最好的祝福

Ema*_*lin 5

我不太确定查询是否真的像你想象的那么快.很可能实际查询仅使用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管理的CursorLoaders.LoaderManager管理游标(打开和关闭它们),在方向更改中保留游标并在后台任务中运行所有内容,因此阻止ui线程没有问题.如果内容发生变化,LoaderManager也会重新查询数据库(请参阅:https://stackoverflow.com/a/5603959/534471).当LoaderManager通知您的片段或您的活动光标已完成加载时,它将调用onLoadFinished()(请参阅:http://developer.android.com/reference/android/support/v4/app/LoaderManager.LoaderCallbacks.html) .

减慢代码速度的不仅仅是查询数据库,还要创建10'000 MarkerElement和另外10'000 LatLng对象.我不知道你的要求,但如果你看到没有这些对象的任何机会,肯定会加速你的代码.消除MarkerElements/LatLng的另一个理想效果是内存使用.对于针对手机的应用,20个具有3个字符串和2个双倍的对象是相当可观的.

使用CursorLoaders和LoaderManager将允许您从光标检索值并直接填充您的ui视图而无需MarkerElements和LatLng.它还允许你懒洋洋地加载.您可以在为其中一个CursorLoaders调用onLoadFinished()时填充视图(除非从非ui线程调用initLoader/restartLoader,否则在ui线程上调用onLoadFinished()).如果一次填充1000个视图太多,要么将查询分解为更小的部分,要么添加一个机制来以10s或100s(对于每个游标)的块填充视图.

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

摘要:

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