如何在单个请求中检索 phone numbers/photo id/firstname/lastname?

How to retrieve phone numbers/photo id/firstname/lastname within a single request?

我目前正在使用这个问题的答案:How to get all contacts first name, last name, email, phone number, etc without duplicates 来检索用户联系人列表,对于每个联系人,所有 phone 号码、名字、姓氏和照片 ID。

我对这个答案的看法是它为每个需要的数据创建一个请求。它在我的应用程序上造成了性能问题。我想从一个请求中检索所有这些信息,但我很难理解 Android 的查询是如何管理的以及我要查找的存储数据在哪里。

我尝试过的例子(我做了很多测试都没有成功,以下是我最后一次尝试的):

    new CursorLoader(
        this,
        ContactsContract.Data.CONTENT_URI,
        null,
        ContactsContract.Data.HAS_PHONE_NUMBER + "!=0 AND (" + ContactsContract.Data.MIMETYPE + "=?)",
        new String[]{ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE},
        ContactsContract.Data.CONTACT_ID)
    ; 

以及我要检索的信息:

        int firstNameCol = cursor.getColumnIndex(CommonDataKinds.StructuredName.GIVEN_NAME);
        int lastNameCol = cursor.getColumnIndex(CommonDataKinds.StructuredName.FAMILY_NAME);
        int photoIdCol = cursor.getColumnIndex(CommonDataKinds.StructuredName.PHOTO_ID);
        int phoneCol = cursor.getColumnIndex(Phone.NUMBER);

该请求有两个问题:

请注意,我不想检索 DISPLAY_NAME,我想要 given_name 和 family_name。另请注意,我希望每个联系人有一个结果,而不是每个 phone 号码有一个结果(即一个结果包含一对多 phone 号码)

有没有想法在单个请求中做到这一点?

编辑:尝试使用来自@pskink 的另一段代码,但我收到 "column '_id' does not exists" 错误

    String[] projection = {
        ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
        ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
        ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
        ContactsContract.CommonDataKinds.StructuredName.PHOTO_ID
    };
    String selection = ContactsContract.Data.MIMETYPE + " in (?, ?, ?, ?)";
    String[] selectionArgs = {
        ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
        ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
        ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
        ContactsContract.CommonDataKinds.StructuredName.PHOTO_ID
    };
    //String sortOrder = ContactsContract.Contacts.SORT_KEY_ALTERNATIVE;

    //Uri uri = ContactsContract.CommonDataKinds.Contactables.CONTENT_URI;
    Uri uri = ContactsContract.Data.CONTENT_URI;
    // ok, let's work...
    return new CursorLoader(
        this, uri, projection, selection, selectionArgs, null
    );

感谢@pskink,我现在可以通过一个快速的单一请求来检索我想要的内容。不幸的是,我不能使用 CursorAdapter,我必须请求整个数据库并将结果存储在一个对象模型中,但是结果非常快所以没关系。

完整代码如下:

public ArrayList<ContactModel> retrieveContactList(){

    ArrayList<ContactModel> list = new ArrayList<>();
    LongSparseArray<ContactModel> array = new LongSparseArray<>();

    Set<String> set = new HashSet<String>();
    set.add(ContactsContract.Data.MIMETYPE);
    set.add(ContactsContract.Data.CONTACT_ID);
    set.add(ContactsContract.Data.PHOTO_ID);
    set.add(ContactsContract.CommonDataKinds.Phone.NUMBER);
    set.add(ContactsContract.CommonDataKinds.Phone.TYPE);
    set.add(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
    set.add(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
    set.add(ContactsContract.Contacts.PHOTO_ID);

    Uri uri = ContactsContract.Data.CONTENT_URI;
    String[] projection = set.toArray(new String[0]);
    String selection = ContactsContract.Data.MIMETYPE + " in (?, ?)";
    String[] selectionArgs = {
        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
    };
    String sortOrder = ContactsContract.Contacts.SORT_KEY_ALTERNATIVE;

    Cursor cursor = this.context.getContentResolver().query(
        uri,
        projection,
        selection,
        selectionArgs,
        sortOrder
    );

    final int mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE);
    final int idIdx = cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
    final int phoneIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
    final int phoneTypeIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
    final int givenNameIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
    final int familyNameIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
    final int photoIdIdx = cursor.getColumnIndex(ContactsContract.Data.PHOTO_ID);

    while (cursor.moveToNext()) {

        long id = cursor.getLong(idIdx);
        ContactModel addressBookContact = array.get(id);

        if (addressBookContact == null) {
            addressBookContact = new ContactModel(id);
            array.put(id, addressBookContact);
            list.add(addressBookContact);
        }

        Long photoId = cursor.getLong(photoIdIdx);
        if (photoId != null){
            addressBookContact.addPhotoId(photoId);
        }

        switch (cursor.getString(mimeTypeIdx)) {
            case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE:
                // row's data: see ContactsContract.CommonDataKinds.Phone
                addressBookContact.addPhone(cursor.getInt(phoneTypeIdx), cursor.getString(phoneIdx));
                break;
            case ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:
                // row's data: see ContactsContract.CommonDataKinds.StructuredName
                addressBookContact.addName(cursor.getString(givenNameIdx), cursor.getString(familyNameIdx));
                break;
        }
    }

    cursor.close();

    return list;
}