安卓:处理大型数据集的ContentProvider,以避免内存限制内存、数据、以避免、ContentProvider

2023-09-05 09:52:45 作者:4.月色如浅梦

我使用的是的ContentProvider 来查询数据库,并返回一个光标被用在 CursorLoader

I am using a ContentProvider to query a database and return a Cursor that is used in a CursorLoader:

ItemsActivity:

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

    ...
}

ItemsContentProvider:

ItemsContentProvider:

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 )重新present数据光标之内。

The activity has a ListView, and I am using a CursorAdapter (updated via the LoaderCallbacks) to represent the data within the cursor.

这是工作的罚款,直到我需要查找在大型数据集中的项目(例如,超过30000行)。观察日志我看到查找超出内存限制和一些行是从游标的最终下降。

This is working fine, until I need to lookup the items in a large data set (for example, over 30,000 rows). Observing the logs I see that the lookup exceeds memory limits and some rows are dropped from the resulting cursor.

我的问题:什么是处理大型数据集使用这样的游标时,最好的办法

My question: what is the best way of handling very large datasets when using cursors like this?

我目前的解决办法是打破在的ContentProvider SQLite的查询与补偿和限制查询的序列,然后用 MergeCursor 类:

My current solution is to break up the SQLite query in the ContentProvider into a sequence of queries with offsets and limits, then combine these queries using the MergeCursor class:

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秒,同时多个查询被执行。

This will load all the data, but there's a long delay while doing the lookups for the first time. The list view is empty for about 5 seconds while multiple queries are performed.

请注意,当我尝试单查询(而不是批量查找),装载几乎是瞬间,虽然有滚动的内存达到限制列表时略有停顿。

Note that when I try a single lookup (rather than batched lookups), the loading is almost instantaneous, although there are slight pauses when scrolling the list as memory limits are reached.

所以:

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

Using a single query: fast list view updating, but scrolling pauses and memory limits reached.

使用次查询:缓慢列表视图更新,但是滚动平滑,没有内存限制达到了

Using batched queries: slow list view updating, but scrolling is smooth and no memory limits reached.

我不知道是否有更好的解决方案,将快速更新的列表视图,但由于滚动列表需要的时候也获取更多的数据。

I'm wondering if there's a better solution that will update the list view quickly, but will also fetch more data as required when scrolling the list.

安卓4.2.1,的Nexus 7

Android 4.2.1, Nexus 7

推荐答案

移动设备不是设计来处理这些大量数据。

Mobile devices are not designed to handle these amounts of data.

不过,如果你真的想加害与你可怜的用户这么大的滚动列表,你可以设计它看作是一个条目仅按需加载的虚拟列表;看到的Andr​​oid无尽的列表。

However, if you really want to inflict such a large scrolling list on your poor users, you can design it as a virtual list where entries are loaded only on demand; see Android Endless List.

请注意:使用 OFFSET 条款是无效的;看到滚动游标了解详细信息。

Note: Using the OFFSET clause is inefficient; see Scrolling Cursor for details.