我已经以编程方式在Android地址簿中创建了一个联系人,其中包含姓名和电话号码。现在我想为这个联系人添加一张照片,但我似乎无法使用它。我没有收到错误消息,但照片似乎没有添加。
如果我创建一个新的联系人照片,照片会正确添加,我也可以更新此联系人的现有照片。唯一的问题是没有照片的联系人。
我已经阅读了多个解决方案here和here,并根据这些答案尝试了几种变体,但都不起作用。我最好的猜测是我对RAW_CONTACT_ID
做错了。谁能找到我的错误?
private void createNewContact()
{
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
builder.withValue(RawContacts.ACCOUNT_TYPE, MY_ACCOUNT_TYPE);
builder.withValue(RawContacts.ACCOUNT_NAME, MY_ACCOUNT_NAME);
ops.add(builder.build());
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValueBackReference(Data.RAW_CONTACT_ID, 0);
builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(StructuredName.GIVEN_NAME, myName);
ops.add(builder.build());
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValueBackReference(Data.RAW_CONTACT_ID, 0);
builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
builder.withValue(Phone.TYPE, Phone.TYPE_WORK);
builder.withValue(Phone.NUMBER, myPhoneNumber);
ops.add(builder.build());
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValueBackReference(Data.RAW_CONTACT_ID, 0);
builder.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
builder.withValue(Photo.PHOTO, myPhotoByteArray);
ops.add(builder.build());
try
{
context.getContentResolver().applyBatch(AUTHORITY, ops);
}
catch (Exception e)
{
// Handle exception
}
}
private static final String BASIC_SELECTION = RawContacts.ACCOUNT_TYPE + "='" + MY_ACCOUNT_TYPE + "'";
private void editContact() {
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(Data.CONTENT_URI);
builder.withSelection(BASIC_SELECTION + " AND " + Data.MIMETYPE + "='" + StructuredName.CONTENT_ITEM_TYPE + "'", null);
builder.withValue(StructuredName.GIVEN_NAME, myName);
ops.add(builder.build());
builder = ContentProviderOperation.newUpdate(Data.CONTENT_URI);
builder.withSelection(BASIC_SELECTION + " AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + " AND " + Phone.TYPE + "='" + Phone.TYPE_WORK + "'", null);
builder.withValue(Phone.NUMBER, myPhoneNumber);
ops.add(builder.build());
if (isContactWithoutPhoto())
{
// Contact without photo: insert new photo
// TODO: this part doesn't work yet!
int rawContactId = getRawContactId();
if (rawContactId != -1)
{
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValue(Data.RAW_CONTACT_ID, rawContactId);
builder.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
builder.withValue(Photo.PHOTO, myPhotoByteArray);
ops.add(builder.build());
}
}
else
{
// Contact already has a photo: update
builder = ContentProviderOperation.newUpdate(Data.CONTENT_URI);
builder.withSelection(BASIC_SELECTION + " AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'", null);
builder.withValue(Photo.PHOTO, myPhotoBytes);
ops.add(builder.build());
}
try
{
context.getContentResolver().applyBatch(AUTHORITY, ops);
}
catch (Exception e)
{
// Handle exception
}
}
private int getRawContactId()
{
int rawContactId = -1;
Cursor cursor = null;
try
{
cursor = App.getContext().getContentResolver().query(RawContacts.CONTENT_URI, null, ACCOUNT_TYPE_SELECTION, null, null);
if (cursor != null && cursor.moveToFirst())
{
rawContactId = cursor.getInt(cursor.getColumnIndex(RawContacts._ID));
}
}
finally
{
if (cursor != null)
{
cursor.close();
}
}
return rawContactId;
}
修改
我只需要一次创建一个联系人,之后只需要定期更新。此联系人保存在自行创建的帐户中,类型为MY_ACCOUNT_TYPE&amp;将MY_ACCOUNT_NAME命名为。因此,每个更新操作的builder.withSelection(BASIC_SELECTION
使用MY_ACCOUNT_TYPE而不是id。
我还尝试在现有联系人的“更新照片”上添加相同的选择。部分,实现它更像其他更新&#39;代码,因为我想确保我只为这个单一联系人更新照片:
int rawContactId = getRawContactId();
if (rawContactId != -1)
{
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withSelection(BASIC_SELECTION + " AND " + Data.MIMETYPE + "='" + Photo.CONTENT_ITEM_TYPE + "'", null);
builder.withValue(Data.RAW_CONTACT_ID, rawContactId);
builder.withValue(Photo.PHOTO, myPhotoByteArray);
ops.add(builder.build());
在这种情况下,应用程序显然会因错误java.lang.IllegalArgumentException: only updates, deletes, and asserts can have selections
而崩溃。已使用BASIC_SELECTION
收集了ID,因此我希望无论如何都能以这种方式更新正确的联系人。
如果有人想知道使用了ContactsContract的哪些(静态)导入:
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.PhoneLookup;
import static android.provider.ContactsContract.AUTHORITY;
import static android.provider.ContactsContract.CommonDataKinds.Note;
import static android.provider.ContactsContract.CommonDataKinds.Phone;
import static android.provider.ContactsContract.CommonDataKinds.StructuredName;
import static android.provider.ContactsContract.Data;
import static android.provider.ContactsContract.RawContacts;
答案 0 :(得分:0)
不要直接访问CommonDataKinds.Photo
,而是使用API提供的帮助程序类DisplayPhoto
。
这个助手类将填充PHOTO
和PHOTO_FILE_ID
,这是您的代码所缺少的。
尝试以下方法:
public void setPhoto(long rawContactId, byte[] photo) {
Uri rawContactPhotoUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
try {
AssetFileDescriptor fd = contentResolver.openAssetFileDescriptor(rawContactPhotoUri, "rw");
OutputStream os = fd.createOutputStream();
os.write(photo);
os.close();
fd.close();
} catch (IOException e) {
Log.e(TAG, "error", e);
}
}
答案 1 :(得分:0)
经过反复试验,我发现RawContactId不正确。 最后,我想到了这个解决方案:使用PhoneLookup._ID检索RawContacts.CONTACT_ID,可以通过phoneNumber进行检索。
// This code stays the same as described in the question (except for some error handling and closing cursors, which I left out for simplicity sake):
private void createNewContact() {
...
}
private static final String BASIC_SELECTION = RawContacts.ACCOUNT_TYPE + "='" + MY_ACCOUNT_TYPE + "'";
private void editContact() {
...
int rawContactId = getRawContactId();
...
}
// The different part is the way to retrieve the RawContactId:
private static final ContentResolver CONTENT_RESOLVER = context.getContentResolver();
private int getRawContactId()
{
String[] projection = {Phone.NUMBER};
Cursor cursor = CONTENT_RESOLVER.query(Phone.CONTENT_URI, projection, BASIC_SELECTION, null, null);
String phoneNumber = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
return getRawContactIdWithPhoneNumber(phoneNumber);
}
private int getRawContactIdWithPhoneNumber(String phoneNumber)
{
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
String[] projection = {PhoneLookup._ID, PhoneLookup.DISPLAY_NAME};
Cursor cursor = CONTENT_RESOLVER.query(uri, projection, BASIC_SELECTION, null, null);
int id = cursor.getInt(cursor.getColumnIndex(PhoneLookup._ID));
return getRawContactIdWithPhoneLookupId(id);
}
private int getRawContactIdWithPhoneLookupId(int id)
{
String[] projection = new String[]{RawContacts._ID};
String selection = RawContacts.CONTACT_ID + "=?";
String[] selectionArgs = new String[]{String.valueOf(id)};
Cursor cursor = CONTENT_RESOLVER.query(RawContacts.CONTENT_URI, projection, selection, selectionArgs, null);
return cursor.getInt(cursor.getColumnIndex(RawContacts._ID));
}