15

私は、人 (具体的には、子供の親または保護者) を表すデータ型を持つ Android アプリを作成しています。関連するデータ フィールドを Android デバイスの連絡先データベースから「インポート」できるようにしたいと考えています。(これはオプションである必要があります。つまり、親/保護者が既に連絡先データベースに存在している必要はなく、新しい親/保護者を追加した場合に連絡先データベースが更新されることもありません。)

これまでのところ、(Intent.ACTION_PICK を使用して) 特定の連絡先を選択する新しいインテントを開始するコードを記述しました。次に、データベース内の特定の連絡先を表す URI を取得します。

残念ながら、次のステップが何であるかはわかりません。これは世界で最も簡単なことのように思えますが、明らかにそうではありません。私は Android 開発者 Web サイトのドキュメントを読み、複数の Android ブックに目を通しました。喜びはありません。

私が取得したい特定の情報は次のとおりです。

  1. 連絡先の名前 (可能であれば姓と名を別々に)

  2. 連絡先の (プライマリ) メールアドレス

  3. 連絡先の携帯電話番号

これは ContentResolver を使用してクエリを実行することで可能になると思いますが、Intent から返された URI を使用してこれを行う方法がわかりません。ドキュメントのほとんどは、連絡先の URI ではなく、連絡先 ID を持っていることを前提としています。また、これが私が望むことを行う正しい方法でさえあると仮定して、クエリの射影にどのような種類のフィールドを入れることができるかわかりません。

これが私の開始コードです:

// In a button's onClick event handler:
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT);

// In onActivityResult:
if (resultCode == RESULT_OK) {
    if (requestCode == PICK_CONTACT) {
        contactURI = data.getData();
        // NOW WHAT?
    }
}
4

3 に答える 3

20

さて、たくさん掘り下げた後、私は自分が答えだと信じているものを見つけました。私が見つけた解決策は、使用している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
}

これが誰かに役立つことを願っています。そして、繰り返しますが、これを行うためのより良い方法があれば、私はすべての耳です。

于 2012-12-29T13:13:00.143 に答える
2
//Add a permission to read contacts data to your application manifest.
<uses-permission android:name="android.permission.READ_CONTACTS"/>

//Use Intent.ACTION_PICK in your Activity 
Intent contactPickerIntent = new Intent(Intent.ACTION_PICK,
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
        startActivityForResult(contactPickerIntent, RESULT_PICK_CONTACT);

//Then Override the onActivityResult() and retrieve the ID,Phone number and Name in the data. 
 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // check whether the result is ok
        if (resultCode == RESULT_OK) {
            // Check for the request code, we might be usign multiple startActivityForReslut
            switch (requestCode) {
            case RESULT_PICK_CONTACT:
               Cursor cursor = null;
        try {
            String phoneNo = null ;
            String name = null;           
            Uri uri = data.getData();            
            cursor = getContentResolver().query(uri, null, null, null, null);
            cursor.moveToFirst();           
            int  phoneIndex =cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
            phoneNo = cursor.getString(phoneIndex); 
            textView2.setText(phoneNo);
        } catch (Exception e) {
            e.printStackTrace();
        }
                break;
            }
        } else {
            Log.e("MainActivity", "Failed to pick contact");
        }
    }

注: Android 2.3 (API レベル 9) より前では、連絡先プロバイダー (上記のような) でクエリを実行するには、アプリで READ_CONTACTS パーミッションを宣言する必要があります (セキュリティとパーミッションを参照)。ただし、Android 2.3 以降、Contacts/People アプリは、結果が返されたときに Contacts Provider から読み取るための一時的なアクセス許可をアプリに付与します。一時的なアクセス許可は、要求された特定の連絡先にのみ適用されるため、READ_CONTACTS アクセス許可を宣言しない限り、インテントの Uri で指定された連絡先以外の連絡先を照会することはできません。

于 2016-02-10T12:40:39.807 に答える