如何在SimpleCursorAdapter或Cursor中插入额外的元素以供Spinner使用?

30
我有一个Spinner,需要展示从数据库中取出的数据列表。这些数据由查询返回给Cursor,再将Cursor传递给Spinner的SimpleCursorAdapter。目前它能正常工作,但我想在这些数据的顶部插入另一项内容。例如,Spinner已经展示了保存在数据库中的用户创建的模板列表,但我想在模板列表的顶部插入“新模板”和“空模板”,并且需要将它们插入到Cursor/SimpleCursorAdapter中。
我考虑过使用ArrayList,并从Cursor中填充ArrayList,但对我来说,Cursor是更好的解决方案,因为它还包含其他相关行的数据。我在互联网上搜索了其他解决方案,并找到一些回答要求使用CursorWrapper来实现此目的,但我找不到一个具体的示例来说明如何使用CursorWrapper来完成我想要的操作。请问有什么方法可以插入一些行到Cursor中或者是否可以提供一个易于理解的CursorWrapper示例呢?谢谢!
3个回答

91

您可以像这样使用MergeCursorMatrixCursor与您的DB cursor组合:

MatrixCursor extras = new MatrixCursor(new String[] { "_id", "title" });
extras.addRow(new String[] { "-1", "New Template" });
extras.addRow(new String[] { "-2", "Empty Template" });
Cursor[] cursors = { extras, cursor };
Cursor extendedCursor = new MergeCursor(cursors);

1
太棒了。这比其他人建议的将光标加载到数组列表中要好得多。谢谢。 - Thupten
需要关闭 extrascursor 游标吗? - ban-geoengineering

2
这是我尝试过的方法。
MatrixCursor m = new MatrixCursor(c.getColumnNames());
Cursor c = DBHelper.rawQuery("Select values from your_table");
MatrixCursor m = new MatrixCursor(c.getColumnNames());

//Use MatrixCursor#addRow here to add before the original cursor

while (c.moveToNext()) {
    //Use MatrixCursor#addRow here to add before the original row
    DBHelper.insertRow(c, m);
    //Use MatrixCursor#addRow here to add after the original row

}
//Use MatrixCursor#addRow here to add after the original cursor

m.addRow(new String[]{col1Val, col2Val, col3Val,..., //to match the number of columns needed});

DBHelper.insertRow()

public final static void insertRow(Cursor from, MatrixCursor to) {
final String columns[] = from.getColumnNames(), values[] = new String[columns.length];
    final int size = columns.length;

    for (int i = 0; i < size; i++) {
        values[i] = getStringFromColumn(from, columns[i]);
    }
    to.addRow(values);
}

使用这种方法,您可以在游标的任何位置添加任意数量的行。即使它没有使用CursorWrapper,它也可以与CursorAdapters或SimpleCursorAdapters一起使用。

2
我尝试了 @naktinis 提供的解决方案,但结果并不是我期望的。我想要实现一个适配器,可以在顶部(索引 0)添加新元素。然而,使用给出的解决方案,新元素确实被添加到了顶部,但只是添加到了 MatrixCursor 的末尾。换句话说,当我动态向 "extras" MatrixCursor 添加行时,我得到了这样的结果:
- "extras" 行 1 - "extras" 行 2 - "extras" 行 3 - "cursor" 行 1 - "cursor" 行 2 - "cursor" 行 3
然而,我真正想要实现的是这样的结果:
- "extras" 行 3 - "extras" 行 2 - "extras" 行 1 - "cursor" 行 1 - "cursor" 行 2 - "cursor" 行 3
换句话说,最近的元素进入顶部(索引 0)。
我通过手动执行以下步骤来实现这一点。请注意,我没有包含任何处理从适配器动态删除元素的逻辑。
private class CollectionAdapter extends ArrayAdapter<String> {

  /**
   * This is the position which getItem uses to decide whether to fetch data from the
   * DB cursor or directly from the Adapter's underlying array. Specifically, any item
   * at a position lower than this offset has been added to the top of the adapter
   * dynamically.
   */
  private int mCursorOffset;

  /**
   * This is a SQLite cursor returned by a call to db.query(...).
   */
  private Cursor mCursor;

  /**
   * This stores the initial result returned by cursor.getCount().
   */
  private int mCachedCursorCount;

  public Adapter(Context context, Cursor cursor) {
    super(context, R.layout.collection_item);
    mCursor = cursor;
    mCursorOffset = 0;
    mCachedCursorCount = -1;
  }

  public void add(String item) {
    insert(item, 0);
    mCursorOffset = mCursorOffset + 1;
    notifyDataSetChanged();
  }

  @Override
  public String getItem(int position) {
    // return the item directly from underlying array if it was added dynamically.
    if (position < mCursorOffset) {
      return super.getItem(position);
    }

    // try to load a row from the cursor.
    if (!mCursor.moveToPosition(position - mCursorOffset)) {
      Log.d(TAG, "Failed to move cursor to position " + (position - mCursorOffset));
      return null; // this shouldn't happen.
    }
    return mCursor.getString(INDEX_COLLECTION_DATA);   
  }

  @Override
  public int getCount() {
    if (mCachedCursorCount == -1) {
      mCachedCursorCount = mCursor.getCount();
    }
    return mCursorOffset + mCachedCursorCount;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接