Добавление строк в Cursor вручную
У меня есть массив телефонных номеров, и я хочу получить соответствующие имена контактов из базы данных контактов.
В массиве телефонных номеров у меня также есть некоторые номера, которые ранее не сохраняются в базе данных контактов. Например:
- 3333333 → Тим
- 5555555 → Jim
- 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 в приведенном выше сценарии. Когда номер телефона не отображается в списке контактов, курсор становится пустым, и каким-то образом, когда я их объединяю, он ничего не способствует. Я хочу иметь курсор следующим образом
Телефон курсора → {tим, Джим, 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
};
Ответы
Ответ 1
Самый простой способ добавить строки в курсор - использовать MatrixCursor и MergeCursor.
Эти два класса из SDK и здесь для решения таких проблем.
В основном, что вы делаете:
- Поместите строки, которые вы хотите добавить, в
MatrixCusror
- Слейте
cursor
и matrixCursor
с помощью MergeCursor
Что-то вроде:
// 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.
Ответ 2
Я использую решение, которое делает трюк для всех моих разных потребностей, и которое проще, чем реализация курсора.
Вот пример, когда мне нужно добавить дополнительные строки "playlist" в 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), поэтому я строю его с массивом дополнительных объектов строк.
Ответ 3
Я знаю это старое сообщение, но это настоящая боль, что строки не могут быть добавлены вручную в Курсор. Я придумал грубое решение. Возможно, это поможет.
Cursor
на самом деле является interface
, и вы можете создать пользовательский class
интерфейс implements
Cursor
.
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
.
Ответ 4
К сожалению, насколько я знаю, вы не можете вручную добавить данные в курсор. Вы должны обрабатывать это по-другому.
Единственный способ, о котором я могу думать, в котором вы можете это сделать, -
- Создайте структуру с необходимыми полями данных.
- Сделайте Arraylist и заполните объекты вашей структуры данными из курсоров и добавьте их в список.
- Теперь добавьте свою информацию о недостающих номерах вручную и добавьте их в список.
- Передайте этот список вашему адаптеру, если он переместит курсор на текущий адаптер. Конечно, вам придется изменить реализацию
cursoradapter
на arrayadapter
.