好吧,大量挖掘后,我发现我所相信的是答案。我发现的解决方案根据您使用的Android API级别而有所不同。然而,他们并不漂亮,所以如果有更好的解决方案,我很想知道。
在任何情况下,第一步是通过对从Intent.ACTION_PICK返回的URI执行查询来获取联系人的ID。当我们在这里时,我们也应该得到显示名称,以及表示联系人是否有电话号码的字符串。 (我们将不再需要他们为现代化的解决方案,但我们需要他们为传统的解决方案。)
String id, name, phone, hasPhone;
int idx;
Cursor cursor = getContentResolver().query(contactUri, null, null, null, null);
if (cursor.moveToFirst()) {
idx = cursor.getColumnIndex(ContactsContract.Contacts._ID);
id = cursor.getString(idx);
idx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
name = cursor.getString(idx);
idx = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
hasPhone = cursor.getString(idx);
}
根据记录,从这个URI返回的列大部分领域的常量表示在ContactsContract.Profile类中(包括从其他接口继承的常量)。不包括PHOTO_FILE_ID,PHOTO_THUMBNAIL_URI或PHOTO_URI(但PHOTO_ID 包含)。
现在我们有了ID,我们需要获取相关数据。第一个(也是最简单的)解决方案是查询一个实体。实体查询一次检索联系人或原始联系人的所有联系人数据。每行代表一个单一的Raw Contact,使用ContactsContract.Contacts.Entity中的常量访问。通常你只关心RAW_CONTACT_ID,DATA1和MIMETYPE。但是,如果分别需要姓氏和名字,则名称MIME类型包含DATA2中的名字和DATA3中的姓氏。
通过将MIMETYPE列与ContactsContract.CommonDataKinds常数进行匹配来加载变量;例如,电子邮件MIME类型在ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE。
// Build the Entity URI.
Uri.Builder b = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, id).buildUpon();
b.appendPath(ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);
URI contactUri = b.build();
// Create the projection (SQL fields) and sort order.
String[] projection = {
ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
ContactsContract.Contacts.Entity.DATA1,
ContactsContract.Contacts.Entity.MIMETYPE };
String sortOrder = ContactsContract.Contacts.Entity.RAW_CONTACT_ID + " ASC";
cursor = getContentResolver().query(contactUri, projection, null, null, sortOrder);
String mime;
int mimeIdx = cursor.getColumnIndex(ContactsContract.Contacts.Entity.MIMETYPE);
int dataIdx = cursor.getColumnIndex(ContactsContract.Contacts.Entity.DATA1);
if (cursor.moveToFirst()) {
do {
mime = cursor.getString(mimeIdx);
if (mime.equalsIgnoreCase(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
email = cursor.getString(dataIdx);
}
if (mime.equalsIgnoreCase(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
phone = cursor.getString(dataIdx);
}
// ...etc.
} while (cursor.moveToNext());
}
不幸的是,实体没有引入unti API 11(Android 3.0的,蜂窝),这意味着这个代码是与在市场上Android设备(在本文写作)的大致65%的不兼容。如果您尝试它,您将从URI获得IllegalArgumentException。
第二种解决方案是建立一个查询字符串,使一个查询每个数据类型要使用:
// Get phone number - if they have one
if ("1".equalsIgnoreCase(hasPhone)) {
cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = "+ id,
null, null);
if (cursor.moveToFirst()) {
colIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
phone = cursor.getString(colIdx);
}
cursor.close();
}
// Get email address
cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " + id,
null, null);
if (cursor.moveToFirst()) {
colIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS);
email = cursor.getString(colIdx);
}
cursor.close();
// ...etc.
很明显,将导致大量的单独的数据库查询这种方式,所以它的不建议出于效率原因。
我已经想出了解决的办法是尽量使用实体查询的版本,赶抛出:IllegalArgumentException,并把遗留代码catch块:
try {
// Build the Entity URI.
Uri.Builder b = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, id).buildUpon();
b.appendPath(ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);
// ...etc...
} catch (IllegalArgumentException e) {
// Get phone number - if they have one
if ("1".equalsIgnoreCase(hasPhone)) {
// ...etc...
} finally {
// If you want to display the info in GUI objects, put the code here
}
我希望这可以帮助别人。而且,如果有更好的方法来做到这一点,我就会全神贯注。
我得到一个警告params [0]这是什么? –
非常感谢您的回答! – Chisko
@GerardGrundy Karl在一个AsyncTask中实现了这个解决方案,由于查询内容解析器的操作可能很长,所以推荐使用这种解决方案。params []数组(可以被命名为你想要的,但是“params”和“args”是通用名称)是数据如何传递到AsyncTask中的。查看[AsyncTask](https://developer.android.com/reference/android/os/AsyncTask.html)文档以获取更多信息。 – Slerig