【问题标题】:Adding rows into Cursor manually手动将行添加到光标中
【发布时间】:2012-04-12 15:51:16
【问题描述】:

我有一个电话号码数组,我想从联系人数据库中获取相应的联系人姓名。

在电话号码数组中,我还有一些以前没有保存到联系人数据库中的号码。例如;

  • 3333333 -> 蒂姆
  • 5555555 -> 吉姆
  • 1111111 -> 未知

我有一个包含上面显示的电话号码的数组,即 phoneArr

int size=phoneArr.size();
if(size>0){
        Cursor[] cursors=new Cursor[size];
        for(int i=0;i<size;i++){
            Uri contactUri1 = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneArr.get(i)));
            cursors[i] = getContentResolver().query(contactUri1, PEOPLE_PROJECTION, null, null, " _id asc limit 1");
        }
        Cursor phones=new MergeCursor(cursors);

phones.getCount() 在上述情况下返回 2。当电话号码未出现在联系人列表中时,光标变为空,并且当我合并它们时,它根本没有任何贡献。我想要的是有一个光标如下

光标电话 -> {Tim, Jim, 1111111}

我想我可以通过手动添加行来做到这一点,如下所示:

Uri contactUri1 = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneArr.get(i)));
cursors[i] = getContentResolver().query(contactUri1, PEOPLE_PROJECTION, null, null, " _id asc limit 1");
if(cursors[i].getCount()==0)
    // add the phone number manually to the cursor

我怎样才能做到这一点?

这里是 PEOPLE_PROJECTION

private static final String[] PEOPLE_PROJECTION = new String[] {
    ContactsContract.PhoneLookup._ID,
    ContactsContract.PhoneLookup.DISPLAY_NAME,
    ContactsContract.PhoneLookup.NUMBER
};

【问题讨论】:

  • 请查看您接受的答案,根据Android SDK目前可用的功能似乎是错误的。
  • 好吧,当我接受答案时,这似乎是合理的。有空我会复习的。

标签: android row android-cursor


【解决方案1】:

不幸的是,据我所知,您无法手动将数据添加到光标。您需要以不同的方式处理此问题。

我能想到的唯一方法是

  • 用您需要的数据字段创建一个结构。
  • 创建一个 Arraylist 并用游标中的数据填充结构中的对象并将它们添加到列表中。
  • 现在手动添加您缺少的号码信息并将它们添加到列表中。
  • 将此列表传递给您的适配器,以防您现在将光标传递给适配器。当然,您必须将您的 cursoradapter 实现更改为 arrayadapter

【讨论】:

  • 这不是我想听到的:) 无论如何感谢您的回答
  • 我知道。这是一个主要的痛苦。我诅咒了很多,因为我多次面对这个问题。但是,如果您确实设法找到一种添加到光标的方法(我真的怀疑),请在这篇文章中分享。作为后备,您可以使用此方法。
【解决方案2】:

在游标中添加行的最简单方法是使用MatrixCursorMergeCursor。 这两个类来自 SDK,用于解决此类问题。

基本上你做的是:

  1. 将要添加的行放入MatrixCusror
  2. 使用MergeCursor 合并您的cursor 和您的matrixCursor

类似:

// Create a MatrixCursor filled with the rows you want to add.
MatrixCursor matrixCursor = new MatrixCursor(new String[] { colName1, colName2 });
matrixCursor.addRow(new Object[] { value1, value2 });

// Merge your existing cursor with the matrixCursor you created.
MergeCursor mergeCursor = new MergeCursor(new Cursor[] { matrixCursor, cursor });

// Use your the mergeCursor as you would use your cursor.

【讨论】:

  • 你会把它放在 bindView 方法的顶部吗?
  • 我认为最好在将光标传递给适配器之前执行此操作。在您提出查询之后。
  • mergeCursor 中添加这个新行的index
  • @Nezam,从上面的例子中,新行将是第一个位置
  • @Nazam,您需要在MatrixCursor 中创建一个名为_id 的索引列。该索引列中的值将由addRow() 设置。它们可以是任何你喜欢的,因为 MatrixCursor 不是 SQL 数据库,它们是否与其他 Cursor 中的 _id 值重叠并不重要。
【解决方案3】:

我使用的解决方案可以满足我所有不同的需求,而且比实现 Cursor 更简单。
这是一个示例,我必须将额外的“播放列表”行添加到从 Mediastore 检索的光标。我在原始光标的第一个索引处添加行:

public class CursorWithExtraPlaylists extends CursorWrapper {

public static final int ID_COLUMN_INDEX = 0;
public static final int NAME_COLUMN_INDEX = 1;

private int mPos = -1;
private Context mContext;
private Playlist[] extras;

public CursorWithExtraPlaylists(Cursor cursor, Context context,
        Playlist[] extras) {
    super(cursor);
    mContext = context;
    this.extras = extras;
}

@Override
public int getCount() {
    return super.getCount() + extras.length;
}

@Override
public int getPosition() {
    return mPos;
}

@Override
public boolean moveToFirst() {
    return moveToPosition(0);
}

@Override
public boolean moveToLast() {
    return moveToPosition(getCount() - extras.length);
}

@Override
public boolean move(int offset) {
    return moveToPosition(mPos + offset);
}

@Override
public boolean moveToPosition(int position) {
    // Make sure position isn't past the end of the cursor
    final int count = getCount();
    if (position >= count) {
        mPos = count;
        return false;
    }
    // Make sure position isn't before the beginning of the cursor
    if (position < 0) {
        mPos = -1;
        return false;
    }
    // Check for no-op moves, and skip the rest of the work for them
    if (position == mPos) {
        return true;
    }

    mPos = position;
    if (mPos > 0) {
        // ok, that concerns super cursor
        return super.moveToPosition(mPos - 1);
    }
    return true;
}

@Override
public boolean moveToNext() {
    return moveToPosition(mPos + 1);
}

@Override
public boolean moveToPrevious() {
    return moveToPosition(mPos - 1);
}

private boolean isPointingOnExtras() {
    if (-1 == mPos || getCount() == mPos) {
        throw new CursorIndexOutOfBoundsException(mPos, getCount());
    }
    if (mPos <= extras.length - 1) {
        // this is a request on an extra value
        return true;
    }
    return false;
}

private Object getExtraValue(int columnIndex) {
    switch (columnIndex) {
    case ID_COLUMN_INDEX:
        return extras[mPos].getId();
    case NAME_COLUMN_INDEX:
        return extras[mPos].getName(mContext);
    }
    return null;
}

@Override
public int getInt(int columnIndex) {
    if (isPointingOnExtras())
        return (Integer) getExtraValue(columnIndex);
    int res = super.getInt(columnIndex);
    return res;
}

@Override
public String getString(int columnIndex) {

    if (isPointingOnExtras())
        return getExtraValue(columnIndex).toString();
    return super.getString(columnIndex);
}

public static class Playlist {
    private int mId;
    private int mNameResId;

    public Playlist(int mId, int nameResId) {
        this.mId = mId;
        this.mNameResId = nameResId;
    }

    public int getId() {
        return mId;
    }

    public String getName(Context mContext) {
        return mContext.getResources().getString(mNameResId);
    }

}
}

原始游标有 2 列(int,String),所以我用一个额外的行对象数组来构造它。

【讨论】:

    【解决方案4】:

    我知道这是一篇旧帖子,但是无法手动将行添加到光标中确实很痛苦。我想出了一个粗略的解决方案。这可能会有所帮助。

    Cursor实际上是一个interface,您可以创建一个自定义class,即implementsCursor接口。

    class ManualCursor implements Cursor{
          // ....
          private Vector<String[]> rows;
    
          public void addRow(String[] values){
                rows.add(values);
          }
    
          // Implement the necessary methods, getString(int), etc.
    
          //....
    }
    

    最后在你的代码中

    if (cursors[i].getCount() == 0){
         cursors[i] = new ManualCursor();
         cursors[i].addRow(rowValues);
    }
    

    应该这样做。但请注意,要实现此功能,您在实现 Cursor 接口时必须谨慎。

    【讨论】:

    • 那行得通,您也可以使用 MatrixCursor,但是您会遇到潜在的内存问题,并且您会删除 RecyclerView 的大型数据列表效率。
    猜你喜欢
    • 2017-11-24
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-21
    • 1970-01-01
    • 2020-08-31
    相关资源
    最近更新 更多