さて、たくさん掘り下げた後、私は自分が答えだと信じているものを見つけました。私が見つけた解決策は、使用しているAndroidAPIレベルによって異なります。しかし、それらはまったくきれいではないので、より良い解決策があれば、私は知りたいです。
いずれの場合も、最初のステップは、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を取得したので、関連するデータを取得する必要があります。最初の(そして最も単純な)解決策は、エンティティを照会することです。エンティティクエリは、連絡先または未加工の連絡先のすべての連絡先データを一度に取得します。各行は、ContactsContract.Contacts.Entityの定数を使用してアクセスされる単一のRaw連絡先を表します。通常は、RAW_CONTACT_ID、DATA1、およびMIMETYPEのみに関心があります。ただし、名前と名前を別々に使用する場合は、Name 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());
}
残念ながら、エンティティはAPI 11(Android 3.0、Honeycomb)まで導入されていませんでした。つまり、このコードは、市場に出回っているAndroidデバイスの約65%と互換性がありません(この記事の執筆時点)。試してみると、URIからIllegalArgumentExceptionが発生します。
2番目の解決策は、クエリ文字列を作成し、使用するデータ型ごとに1つのクエリを作成することです。
// 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
}
これが誰かに役立つことを願っています。そして、繰り返しますが、これを行うためのより良い方法があれば、私はすべての耳です。