我正在使用 aContentProvider
来查询数据库并返回 aCursor
中使用的 a CursorLoader
:
项目活动:
public class ItemsActivity extends SherlockActivity implements LoaderCallbacks<Cursor> {
@Override
public void onCreate(Bundle savedInstance) {
....
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
...
}
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
return new CursorLoader(getApplicationContext(), itemsListUri, ...);
}
...
}
项目内容提供者:
public Cursor query(Uri uri, String[] projection, String selection, ...) {
SqliteQueryBuilder builder = new SqliteQueryBuilder();
builder.setTables(ItemsTable.NAME);
return builder.query(db, projection, selection, ...);
}
该活动有一个ListView
,我正在使用一个CursorAdapter
(通过更新LoaderCallbacks
)来表示游标内的数据。
这工作正常,直到我需要在大型数据集中查找项目(例如,超过 30,000 行)。观察日志,我发现查找超出了内存限制,并且从结果游标中删除了一些行。
我的问题:当使用这样的游标时,处理非常大的数据集的最佳方法是什么?
我当前的解决方案是将 SQLite 查询ContentProvider
分解为具有偏移量和限制的查询序列,然后使用MergeCursor
类组合这些查询:
private static final int LIMIT = 5000;
// Ignoring projection, selection, etc for simplicity here
public Cursor query(Uri uri, String projection, String selection, ...) {
List<Cursor> cursors = newList();
int offset = 0;
Cursor c = db.rawQuery("select * from items limit " + LIMIT + " offset " + offset, null);
while (c.getCount() > 0) {
cursors.add(c);
offset += c.getCount();
c = db.rawQuery("select * from items limit " + LIMIT + " offset " + offset, null);
}
return createMergedCursor(cursors);
}
private Cursor createMergedCursors(List<Cursor> cursors) {
if (cursors.size() == 1) {
return cursors.get(0);
}
return new MergeCursor(toCursorsArray(cursors));
}
这将加载所有数据,但在第一次进行查找时会有很长的延迟。执行多个查询时,列表视图大约 5 秒为空。
请注意,当我尝试单个查找(而不是批量查找)时,加载几乎是瞬时的,尽管在达到内存限制时滚动列表时会有轻微的暂停。
所以:
使用单个查询:快速列表视图更新,但达到滚动暂停和内存限制。
使用批处理查询:列表视图更新缓慢,但滚动很流畅,没有达到内存限制。
我想知道是否有更好的解决方案可以快速更新列表视图,但在滚动列表时也会根据需要获取更多数据。
安卓 4.2.1,Nexus 7