这是如何在地址簿上正确将照片设置为联系人吗?



Background

假设我通过使用通讯簿上的某些查询找到了联系人。通过执行查询从特定帐户(如WhatsApp(获取联系信息来找到它,正如我在这里所写的那样。

现在我有一个图像,我希望用它来更新联系人的照片。

问题所在

我根据我在StackOverflow上找到的东西创建了代码,更新了联系人照片。

问题是,一些用户声称它什么都不做。我不确定是什么原因造成的。也许访问联系人的方式不好(id/查找键?也许我需要获得一个额外的地址簿字段。也许查询本身是错误的...

我在弄清楚此问题的原因时遇到了问题,因为我无法重现它,大多数用户也是如此。

代码

这是我所做的:

final ArrayList<ContentProviderOperation> ops = new ArrayList<>();
final String lookupKey=...;
try {
FileInputStream fileInputStream = new FileInputStream(file);
final byte[] photoByteArray = new byte[(int) file.length()];
fileInputStream.read(photoByteArray);
fileInputStream.close();
final Builder builder = ContentProviderOperation.newUpdate(Data.CONTENT_URI);
builder.withSelection(Data.LOOKUP_KEY + "=?" + " AND " + Data.MIMETYPE + "=?", new String[]{lookupKey, Photo.CONTENT_ITEM_TYPE});
builder.withValue(Photo.PHOTO, photoByteArray);
ops.add(builder.build());
file.delete();
} catch (IOException e) {
e.printStackTrace();
}
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops )

问题

代码有什么问题吗?

我应该以不同的方式更新联系人吗?

为什么有些用户无法更新?查找键还不够吗?它会更新错误的数据吗?

我在某处读到我可能需要使用 RAW 联系人 ID,但找不到确切的操作。查询然后更新/插入?

有人建议开发人员应考虑使用其应用程序的帐户来保存照片,而不是更新,因为这可能会导致问题。是真的吗?

我在代码中看到了许多可能的问题:

  1. 假设为该联系人存储了现有照片(您正在使用newUpdate(,以防当前没有照片,您应该改为newInsert
  2. 您应该更新/插入特定的 RawContact,您编写的内容会更新所有联系人的 RawContacts 照片数据,某些 RawContacts 可能具有只读状态,并且不允许您的应用程序对其进行修改。
  3. 处理照片,尤其是将它们存储到联系人数据库中是一项非常耗费内存的操作,对于某些设备,它可能会在OutOfMemoryError上崩溃,要么是因为它们的 RAM 非常有限,要么是因为内存当前被其他东西大量使用。您应该使用 try/catch 包装整个代码,包括 applyBatch,并捕获所有异常/错误并将它们报告给日志,最好也报告到您的错误报告库(Firebase/crashlytics/等(
  4. 您只是更新原始数据PHOTO字段,您还应该更新PHOTO_FILE_ID字段,因为某些应用程序可能会选择读取PHOTO_FILE_ID并从中获取照片。
  5. 您没有将新照片设置为其联系人的SUPER_PRIMARY,因此,如果同一联系人中的其他 RawContact 也有照片,则它可能"获胜",并且是该联系人的主要照片。

以下是应该有帮助的代码:

// To simplify the code i didn't worry about try/catch, freeing resources, 
// or running slow queries on the main thread, make sure your code does!
public ContentProviderOperation setPhoto(int contactId, byte[] photoByteArray) {
long rawId = getRawId(contactId);
ContentProviderOperation.Builder builder;
String selection = Data.RAW_CONTACT_ID + " = '" + rawId + "' AND " + Data.MIMETYPE + "= '" + Photo.CONTENT_ITEM_TYPE + "'";
Cursor cur = contentResolver.query(Data.CONTENT_URI, new String[]{ Data._ID }, selection, null, null);
if (cur.moveToFirst()) {
// this RawContact already has a photo!
Long photoDataId = cur.getLong(0);
Uri uri = ContentUris.withAppendedId(Data.CONTENT_URI, photoDataId);
builder = ContentProviderOperation.newUpdate(uri);
} else {
// this RawContact has no photo.
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValue(Data.RAW_CONTACT_ID, rawId);
}
builder.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
builder.withValue(Data.IS_SUPER_PRIMARY, 1);
builder.withValue(Data.IS_PRIMARY, 1);
builder.withValue(Photo.PHOTO, photoByteArray);
builder.withValue(Photo.PHOTO_FILE_ID, null);
return builder.build();
}
private long getRawId(long contactId) {
String selection = RawContacts.CONTACT_ID + "='" + contactId + "'";
Cursor cur = contentResolver.query(RawContacts.CONTENT_URI, new String[]{ RawContacts._ID }, selection, null, null);
try {
if (cur.moveToNext()) {
return cur.getLong(0);
}
} finally {
cur.close();
}
return 0;
}

最新更新