Android 多选联系人实现求新方案(基于ContactContract)
Hey there! I see you're looking to update your Android multi-contact selection implementation—since the old PICK_CONTENT approach is pretty restrictive for picking multiple contacts, let's walk through modern, reliable ways to get this done.
1. First: Handle Permissions Properly
Before accessing contacts, you need to request the required runtime permission (Android 6.0+). The core permission you'll need is READ_CONTACTS:
private static final int REQUEST_READ_CONTACTS = 100; private void requestContactsAccess() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_READ_CONTACTS); } else { // Permission granted, launch the picker startMultiContactPicker(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_READ_CONTACTS) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { startMultiContactPicker(); } else { Toast.makeText(this, "We need contact access to let you select contacts", Toast.LENGTH_SHORT).show(); } } }
2. Launch the System Multi-Contact Picker
Instead of the single-selection ACTION_PICK with standard URIs, use CONTENT_MULTIPLE_CONTENT_URI to enable multi-selection:
private static final int REQUEST_MULTI_PICK = 200; private void startMultiContactPicker() { Intent pickerIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_MULTIPLE_CONTENT_URI); startActivityForResult(pickerIntent, REQUEST_MULTI_PICK); }
3. Process Selected Contacts in onActivityResult
Once the user selects contacts, parse the result and store them in your array. Here's how to extract names, contact IDs, and phone numbers:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_MULTI_PICK && resultCode == RESULT_OK && data != null) { ArrayList<Contact> selectedContacts = new ArrayList<>(); Uri[] selectedUris = data.getParcelableArrayExtra(Intent.EXTRA_STREAM); if (selectedUris != null) { for (Uri contactUri : selectedUris) { // Query basic contact details Cursor contactCursor = getContentResolver().query(contactUri, new String[]{ ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY, ContactsContract.Contacts.HAS_PHONE_NUMBER }, null, null, null); if (contactCursor != null && contactCursor.moveToFirst()) { String contactId = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts._ID)); String name = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)); boolean hasPhone = contactCursor.getInt(contactCursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0; // Fetch phone number if available String phoneNumber = ""; if (hasPhone) { Cursor phoneCursor = getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER}, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{contactId}, null); if (phoneCursor != null && phoneCursor.moveToFirst()) { phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); phoneCursor.close(); } } selectedContacts.add(new Contact(name, phoneNumber)); contactCursor.close(); } } } // Now selectedContacts holds all your picked contacts—use it as needed! Log.d("ContactPicker", "Selected " + selectedContacts.size() + " contacts"); } } // Helper class to store contact data class Contact { String name; String phoneNumber; public Contact(String name, String phoneNumber) { this.name = name; this.phoneNumber = phoneNumber; } }
4. Alternative: Build a Custom Contact Picker
If you want full control over the UI (to avoid inconsistent system picker behavior across devices), you can query the Contacts Provider directly and build your own selection UI with a RecyclerView and checkboxes:
private ArrayList<Contact> fetchAllContacts() { ArrayList<Contact> allContacts = new ArrayList<>(); String[] projection = { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY, ContactsContract.Contacts.HAS_PHONE_NUMBER }; Cursor cursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, projection, null, null, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC"); if (cursor != null) { while (cursor.moveToNext()) { String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)); boolean hasPhone = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0; String phone = ""; if (hasPhone) { Cursor phoneCursor = getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER}, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{contactId}, null); if (phoneCursor != null) { if (phoneCursor.moveToFirst()) { phone = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); } phoneCursor.close(); } } allContacts.add(new Contact(name, phone)); } cursor.close(); } return allContacts; }
You can then populate this list into a RecyclerView with checkbox items, letting users select multiple contacts and store the selected ones in your array.
Quick Notes
- For Android 13+, you can also use
READ_PHONE_NUMBERSif you only need phone numbers, butREAD_CONTACTSis more universally useful. - Always close cursors after use to avoid memory leaks.
- System pickers can vary by manufacturer—custom pickers guarantee a consistent user experience.
内容的提问来源于stack exchange,提问作者user9523705

