14

人物(具体的には、子供の親または保護者)を表すデータ型を持つAndroidアプリケーションを作成しています。私は、Androidデバイスの連絡先データベースから関連するデータフィールドを「インポート」できるようにしたいと考えています。 (これはオプションである必要があります。つまり、親/保護者が既に連絡先データベースに登録されている必要はなく、連絡先データベースも更新されます)Intent.ACTION_PICKから返されたURIの特定の連絡先情報を取得します。

これまでのところ、私はIntent.ACTION_PICKを使って特定のContactを選択する新しいIntentを開始するコードを書いています。次に、データベース内の特定のContactを表すURIを取得します。

残念ながら、私は次のステップが何であるか分かりません。これは世界で最も単純なことであるべきだが、明らかにそうではないようだ。私はAndroidデベロッパーのウェブサイトのドキュメントを読んでおり、複数のAndroidブックを見てきました。喜びはありません。

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

  1. 連絡先の名前(最初、可能な場合は別途続く)

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

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

I 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? 
    } 
} 

答えて

14

このように、です。

前述したように、ContactsContract.Contacts.EntityクラスはAPI 11まで使用できませんでした。しかし、ContactsContract.DataクラスはAPI 5で利用できるようになりました。そのクラスは、ほとんどの場合同じ方法で使用できますエンティティクラス。

私のコードを更新しました。これはEntityクラスのコードと非常によく似ており、ほとんど同じように動作します。しかし、私はジンジャーブレッドを実行している私の携帯電話でそれをテストして、それは正常に動作します。最初のクエリからContactsContract.Data.RAW_CONTACT_IDを取得する方法があるように思えませんし、そのIDを使用して、例えばから入手IDと同じないです:私がしなければならなかった

1つの変更はこれですContactsContract.Contacts._ID。代わりに、私はContactsContract.Contacts.DISPLAY_NAME定数について質問しました。これは、ほとんどすべてのContactsContractクラスで一貫しています。

 Cursor cursor; // Cursor object 
     String mime; // MIME type 
     int dataIdx; // Index of DATA1 column 
     int mimeIdx; // Index of MIMETYPE column 
     int nameIdx; // Index of DISPLAY_NAME column 

     // Get the name 
     cursor = getContentResolver().query(params[0], 
       new String[] { ContactsContract.Contacts.DISPLAY_NAME }, 
       null, null, null); 
     if (cursor.moveToFirst()) { 
      nameIdx = cursor.getColumnIndex(
        ContactsContract.Contacts.DISPLAY_NAME); 
      name = cursor.getString(nameIdx); 

      // Set up the projection 
      String[] projection = { 
        ContactsContract.Data.DISPLAY_NAME, 
        ContactsContract.Contacts.Data.DATA1, 
        ContactsContract.Contacts.Data.MIMETYPE }; 

      // Query ContactsContract.Data 
      cursor = getContentResolver().query(
        ContactsContract.Data.CONTENT_URI, projection, 
        ContactsContract.Data.DISPLAY_NAME + " = ?", 
        new String[] { name }, 
        null); 

      if (cursor.moveToFirst()) { 
       // Get the indexes of the MIME type and data 
       mimeIdx = cursor.getColumnIndex(
         ContactsContract.Contacts.Data.MIMETYPE); 
       dataIdx = cursor.getColumnIndex(
         ContactsContract.Contacts.Data.DATA1); 

       // Match the data to the MIME type, store in variables 
       do { 
        mime = cursor.getString(mimeIdx); 
        if (ContactsContract.CommonDataKinds.Email 
          .CONTENT_ITEM_TYPE.equalsIgnoreCase(mime)) { 
         email = cursor.getString(dataIdx); 
        } 
        if (ContactsContract.CommonDataKinds.Phone 
          .CONTENT_ITEM_TYPE.equalsIgnoreCase(mime)) { 
         phone = cursor.getString(dataIdx); 
         phone = PhoneNumberUtils.formatNumber(phone); 
        } 
       } while (cursor.moveToNext()); 
      } 
     } 
+0

私はparams [0]の警告を受け取りますか? –

+0

あなたの答えに多くの感謝! – Chisko

+0

@GerardGrundy Karlは、AsyncTask内でこのソリューションを実装しています。これは、コンテンツリゾルバにクエリを実行する際に長時間実行される可能性があるため推奨されます。params []配列(あなたが望む名前でも構いませんが、 "params"と "args"は共通名です)は、データがAsyncTaskにどのように渡されるかです。詳細については、[AsyncTask](https://developer.android.com/reference/android/os/AsyncTask.html)のドキュメントを参照してください。 – Slerig

16

さて、掘りたくさんの後、私は私が答えであると信じるものを見つけました。私が見つけたソリューションは、使用している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を取得しましたので、関連するデータを取得する必要があります。最初の(そして最も簡単な)解決策は、エンティティを照会することです。エンティティクエリは、連絡先または生の連絡先のすべての連絡先データを一度に取得します。各行は、ContactsContract.Contacts.Entityの定数を使用してアクセスされる1つのRaw Contactを表します。通常、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()); 
} 

残念なことに、エンティティは、このコードは、(これを書いているような)市場におけるAndroidデバイスの約65%と非互換であることを意味unti API 11(アンドロイド3.0、ハニカム)、導入されませんでした。試してみると、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. 

明らかに、この方法は、別々のデータベースクエリの多くになります:

第2の解決策は、クエリ文字列を構築し、各データは、使用したいタイプごとに1つのクエリを作ることです効率の理由から推奨されません。私はこれが誰かの役に立てば幸い

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 
} 

私が作ってみたソリューションは、エンティティのクエリを使用するバージョンを試してみてください、IllegalArgumentExceptionをキャッチし、catchブロック内のレガシーコードを配置することです。そして、もう一度、これを行う良い方法があれば、私はすべての耳です。

+0

この回答に基づいてありがとう、私は 'エンティティ'テーブルの力をunrestood – DoruChidean

1
//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アプリは、結果を返すときに連絡先プロバイダからの読み込みを一時的に許可します。一時的な権限は要求された特定の連絡先にのみ適用されるため、READ_CONTACTS権限を宣言しないかぎり、インテントのUriで指定された連絡先以外の連絡先を照会することはできません。

関連する問題