Android:在ContentProvider中处理非常大的数据集以避免内存限制

Joh*_*zen 2 sqlite android android-contentprovider android-cursorloader

我使用a ContentProvider来查询数据库并返回一个Cursor用于CursorLoader:

ItemsActivity:

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, ...); 
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

ItemsContentProvider:

public Cursor query(Uri uri, String[] projection, String selection, ...) {
    SqliteQueryBuilder builder = new SqliteQueryBuilder();
    builder.setTables(ItemsTable.NAME);
    return builder.query(db, projection, selection, ...);
}
Run Code Online (Sandbox Code Playgroud)

活动有一个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));
}
Run Code Online (Sandbox Code Playgroud)

这将加载所有数据,但是第一次执行查找时会有很长的延迟.执行多个查询时,列表视图为空约5秒钟.

请注意,当我尝试单个查找(而不是批量查找)时,加载几乎是即时的,尽管在达到内存限制时滚动列表时会有轻微的暂停.

所以:

使用单个查询:快速列表视图更新,但滚动暂停和内存限制已达到.

使用批处理查询:慢速列表视图更新,但滚动顺畅且没有达到内存限制.

我想知道是否有更好的解决方案可以快速更新列表视图,但是在滚动列表时也会根据需要获取更多数据.

Android 4.2.1,Nexus 7

CL.*_*CL. 5

移动设备不是为处理这些数据量而设计的.

但是,如果您确实想要在可怜的用户上创建如此大的滚动列表,则可以将其设计为虚拟列表,其中只根据需要加载条目; 请参阅Android Endless List.

注意:使用该OFFSET子句效率低下; 有关详细信息,请参阅滚动光标.