You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android按公司和姓名过滤ContactsContract.Data并实现记录去重问题

解决Android ContactsContract.Data查询返回重复联系人记录的问题

问题原因

你当前查询的ContactsContract.Data表是存储联系人所有数据条目的表(比如一个联系人可能有多条公司信息、邮箱、电话等记录)。当你按Organization.MIMETYPE过滤时,同一个联系人如果有多个组织相关的条目,就会返回多条CONTACT_ID相同的记录。

解决方案

有两种可靠的方式实现每个联系人仅返回一条记录:


方案1:改用ContactsContract.Contacts表查询(推荐)

ContactsContract.Contacts表本身就是按联系人维度存储的,每个联系人对应一条记录。通过子查询过滤出符合公司条件的联系人,同时保留姓名过滤逻辑:

private static final Uri URI = ContactsContract.Contacts.CONTENT_URI;

@SuppressLint("InlinedApi")
private static final String[] PROJECTION = {
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.CONTACT_ID,
        ContactsContract.Contacts.LOOKUP_KEY,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
};

// 使用EXISTS子查询过滤存在符合条件公司信息的联系人
private static final String SELECTION =
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" +
        " AND EXISTS (" +
            "SELECT 1 FROM " + ContactsContract.Data.TABLE_NAME + " d " +
            "WHERE d." + ContactsContract.Data.CONTACT_ID + " = " + ContactsContract.Contacts._ID +
            " AND d." + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Organization.MIMETYPE + "'" +
            " AND d." + ContactsContract.CommonDataKinds.Organization.COMPANY + " LIKE ?" +
        ")";

private static final String SORT_ORDER =
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC";

@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
    String contactsFilter = getFilter(contactsSearch);
    String companyFilter = getFilter(companySearch);

    return new CursorLoader(
            getActivity(),
            URI,
            PROJECTION,
            SELECTION,
            new String[] { contactsFilter, companyFilter},
            SORT_ORDER
    );
}

方案2:在Data表查询中添加去重逻辑

如果坚持使用ContactsContract.Data表,需要去掉会导致行唯一的Data._ID字段,并添加去重参数:

  1. 修改投影字段(移除Data._ID,因为每个数据项的_ID唯一,会导致去重失效):
@SuppressLint("InlinedApi")
private static final String[] PROJECTION = {
        ContactsContract.Data.CONTACT_ID,
        ContactsContract.Data.LOOKUP_KEY,
        ContactsContract.Data.DISPLAY_NAME_PRIMARY
};
  1. 构建带去重参数的URI:
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
    String contactsFilter = getFilter(contactsSearch);
    String companyFilter = getFilter(companySearch);

    // 添加distinct参数实现去重
    Uri distinctUri = ContactsContract.Data.CONTENT_URI.buildUpon()
            .appendQueryParameter("distinct", "true")
            .build();

    return new CursorLoader(
            getActivity(),
            distinctUri,
            PROJECTION,
            SELECTION,
            new String[] { contactsFilter, companyFilter},
            SORT_ORDER
    );
}

或者也可以使用GROUP BY CONTACT_ID的方式,需要调整投影为聚合字段(比如取最小的_ID):

@SuppressLint("InlinedApi")
private static final String[] PROJECTION = {
        "MIN(" + ContactsContract.Data._ID + ") AS _id", // 聚合取该联系人的第一条数据ID
        ContactsContract.Data.CONTACT_ID,
        ContactsContract.Data.LOOKUP_KEY,
        ContactsContract.Data.DISPLAY_NAME_PRIMARY
};

private static final String SELECTION =
        ContactsContract.Data.DISPLAY_NAME_PRIMARY + " LIKE ?" +
        " AND " + ContactsContract.Data.MIMETYPE + " = " + ContactsContract.CommonDataKinds.Organization.MIMETYPE +
        " AND " + ContactsContract.CommonDataKinds.Organization.COMPANY + " LIKE ?" +
        " GROUP BY " + ContactsContract.Data.CONTACT_ID; // 按CONTACT_ID分组

效果验证

修改后查询返回的Cursor中,每个CONTACT_ID和LOOKUP_KEY只会对应一条记录,符合你的需求。

内容的提问来源于stack exchange,提问作者CompEng88

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 11:50:31