从安卓手机获取匹配的联系人邮箱和手机

Posted

技术标签:

【中文标题】从安卓手机获取匹配的联系人邮箱和手机【英文标题】:Obtain matching contact email and phone from android phone 【发布时间】:2016-05-17 14:04:56 【问题描述】:

我已经设法通过使用我找到的 ContactContract 示例从手机中提取联系人详细信息,但我注意到我手机上的大多数人都有一个唯一的 ID 键,分别与他们的电子邮件和电话号码相关联。例如,当我从数据库中提取 Alan 的联系方式时,即使它们是同一个人的,也会将其拆分如下:

key     name   email            phone
20121   Alan   alan@gmail.com   null
20133   Alan   null             04xxxxxxxx

那么电话如何管理与联系人中所有这些不同键的关联(我假设它必须有一个单独的表)?有没有办法获得这个关联?因为我不能只尝试匹配姓名,因为人们可以有完全相同的姓名,所以您必须将它们分开,因为它们是如何存储在您的手机联系人上的。

(或者混乱的情况是由于所有应用程序都能够将联系人相关详细信息保存到手机上的同一个数据库中?)

我的代码如下所示(我忘记了从哪里获得此代码,但 getDetailedContactList 函数返回了上述问题的联系人列表):

public static String CONTACT_ID_URI = ContactsContract.Contacts._ID;
public static String DATA_CONTACT_ID_URI = ContactsContract.Data.CONTACT_ID;
public static String MIMETYPE_URI = ContactsContract.Data.MIMETYPE;
public static String EMAIL_URI = ContactsContract.CommonDataKinds.Email.DATA;
public static String PHONE_URI = ContactsContract.CommonDataKinds.Phone.DATA;
public static String NAME_URI = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ? ContactsContract.Data.DISPLAY_NAME_PRIMARY : ContactsContract.Data.DISPLAY_NAME;
public static String PICTURE_URI = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ? ContactsContract.Contacts.PHOTO_THUMBNAIL_URI : ContactsContract.Contacts.PHOTO_ID;

public static String MAIL_TYPE = ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE;
public static String PHONE_TYPE = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;

public Cursor getContactCursor(String stringQuery, String sortOrder) 

    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
    Log.e(TAG, "ContactCursor search has started...");

    Long t0 = System.currentTimeMillis();

    Uri CONTENT_URI;

    if (stringQuery == null)
        CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
    else
        CONTENT_URI = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode(stringQuery));

    String[] PROJECTION = new String[]
            CONTACT_ID_URI,
            NAME_URI,
            PICTURE_URI
    ;

    String SELECTION = NAME_URI + " NOT LIKE ?";
    String[] SELECTION_ARGS = new String[]"%" + "@" + "%";

    Cursor cursor = getContentResolver().query(CONTENT_URI, PROJECTION, SELECTION, SELECTION_ARGS, sortOrder);

    Long t1 = System.currentTimeMillis();

    Log.e(TAG, "ContactCursor finished in " + (t1 - t0) / 1000 + " secs");
    Log.e(TAG, "ContactCursor found " + cursor.getCount() + " contacts");
    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");

    return cursor;


public Cursor getContactDetailsCursor() 

    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
    Log.e(TAG, "ContactDetailsCursor search has started...");

    Long t0 = System.currentTimeMillis();

    String[] PROJECTION = new String[]
            DATA_CONTACT_ID_URI,
            MIMETYPE_URI,
            EMAIL_URI,
            PHONE_URI
    ;

    String SELECTION = NAME_URI + " NOT LIKE ?" + " AND " + "(" + MIMETYPE_URI + "=? " + " OR " + MIMETYPE_URI + "=? " + ")";

    String[] SELECTION_ARGS = new String[]"%" + "@" + "%", ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;

    Cursor cursor = getContentResolver().query(
            ContactsContract.Data.CONTENT_URI,
            PROJECTION,
            SELECTION,
            SELECTION_ARGS,
            null);

    Long t1 = System.currentTimeMillis();

    Log.e(TAG, "ContactDetailsCursor finished in " + (t1 - t0) / 1000 + " secs");
    Log.e(TAG, "ContactDetailsCursor found " + cursor.getCount() + " contacts");
    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");

    return cursor;


public List<ContactViewModel> getDetailedContactList(String queryString) 

    /**
     * First we fetch the contacts name and picture uri in alphabetical order for
     * display purpose and store these data in HashMap.
     */

    Cursor contactCursor = getContactCursor(queryString, NAME_URI);
    if(contactCursor.getCount() == 0)
        contactCursor.close();
        return new ArrayList<>();
    

    List<Integer> contactIds = new ArrayList<>();

    if (contactCursor.moveToFirst()) 
        do 
            contactIds.add(contactCursor.getInt(contactCursor.getColumnIndex(CONTACT_ID_URI)));
         while (contactCursor.moveToNext());
    

    HashMap<Integer, String> nameMap = new HashMap<>();
    HashMap<Integer, String> pictureMap = new HashMap<>();

    int idIdx = contactCursor.getColumnIndex(CONTACT_ID_URI);

    int nameIdx = contactCursor.getColumnIndex(NAME_URI);
    int pictureIdx = contactCursor.getColumnIndex(PICTURE_URI);

    if (contactCursor.moveToFirst()) 
        do 
            nameMap.put(contactCursor.getInt(idIdx), contactCursor.getString(nameIdx));
            pictureMap.put(contactCursor.getInt(idIdx), contactCursor.getString(pictureIdx));
         while (contactCursor.moveToNext());
    

    /**
     * Then we get the remaining contact information. Here email and phone
     */

    Cursor detailsCursor = getContactDetailsCursor();

    HashMap<Integer, String> emailMap = new HashMap<>();
    HashMap<Integer, String> phoneMap = new HashMap<>();

    idIdx = detailsCursor.getColumnIndex(DATA_CONTACT_ID_URI);
    int mimeIdx = detailsCursor.getColumnIndex(MIMETYPE_URI);
    int mailIdx = detailsCursor.getColumnIndex(EMAIL_URI);
    int phoneIdx = detailsCursor.getColumnIndex(PHONE_URI);

    String mailString;
    String phoneString;

    if (detailsCursor.moveToFirst()) 
        do 

            /**
             * We forget all details which are not correlated with the contact list
             */

            if (!contactIds.contains(detailsCursor.getInt(idIdx))) 
                continue;
            

            if(detailsCursor.getString(mimeIdx).equals(MAIL_TYPE))
                mailString = detailsCursor.getString(mailIdx);

                /**
                 * We remove all double contact having the same email address
                 */

                if(!emailMap.containsValue(mailString.toLowerCase()))
                    emailMap.put(detailsCursor.getInt(idIdx), mailString.toLowerCase());

             else 
                phoneString = detailsCursor.getString(phoneIdx);
                phoneMap.put(detailsCursor.getInt(idIdx), phoneString);
            

         while (detailsCursor.moveToNext());
    

    contactCursor.close();
    detailsCursor.close();

    /**
     * Finally the contact list is build up
     */

    List<ContactViewModel> contacts = new ArrayList<>();

    Set<Integer> emailsKeySet = emailMap.keySet();
    Set<Integer> phoneKeySet = phoneMap.keySet();

    for (Integer key : contactIds) 

        if( (!emailsKeySet.contains(key) && !phoneKeySet.contains(key))
            || (emailMap.get(key) == null && phoneMap.get(key) == null)
            || mContactDB.isContactExisted(key))
        
            continue;
        

        contacts.add(new ContactViewModel(key, nameMap.get(key), emailMap.get(key)));
    

    return contacts;

【问题讨论】:

【参考方案1】:

尝试下面的代码来获取特定人员的联系电话。

ContentResolver cr = getContentResolver(); 
Cursor cursor = cr.query(Phone.CONTENT_URI, null, Phone.DISPLAY_NAME + "=?", new String[]contactName, null);
if(cursor.getCount() > 0)
cursor.moveToFirst();
do 
   String number = cursor.getString(mCursor.getColumnIndex(Phone.NUMBER));
while (cursor.moveToNext() ); 

【讨论】:

我的问题是同一个人分别拥有一个唯一的电子邮件和电话密钥。我想知道android是如何将同一个人的这两个单独的条目链接在一起的。 不要合并两个联系人的电子邮件和电话号码,尽管它们可能具有相同的名称。让用户选择从本地联系人中合并它。一旦用户将电子邮件和艾伦的号码合并。您的代码非常适合拥有单个对象并始终与手机的本机联系人链接。除非您有任何特定的硬性理由,否则建议您关注联系人 ID。这是建议而不是柜台。在您的示例本身中,您可以考虑两个不同的联系人中的两个不同的人,他们的名字与“Allan”相同。现在如果你将电子邮件和电话号码合并,它是正确的还是错误的? 不确定我们是否相互理解。所以我会改写。在我的 android 联系人中,Alan 将电子邮件和电话链接并正确显示在电话簿中。当我编写上面的代码来提取信息时,我只能将其视为具有独立键的两个独立条目。那么我如何获得有关此人的电子邮件和电话之间联系的信息(因为用户已经选择在通讯录中合并此信息)。 尝试从此链接获取详细信息。类似问题的参考***.com/questions/11860475/…【参考方案2】:

Android 建议使用内容解析器和内容提供者在应用程序之间提供良好打包的数据。您可能不应该乱搞数据库本身,而且它显然不是在设计时考虑到这一点的(正如您的经验所证明的那样)。

相反,您应该使用内容解析器来查询 Android ContactsContract 以找到您需要的内容。有一个名为ContactsContract.Contacts 的类听起来像是您需要的入口点。对类的查询返回的每条记录都代表一个联系人。

更多详情请参阅Content Providers Developer Guide。

【讨论】:

实际上 ContactsContract 正是我正在使用的。也许我会改写一下这个问题。 我也添加了代码,所以也许你可以看看我是否可以做出任何改变来解决这个问题。 好的。在这种情况下,您确定联系人(在您的示例中为“Alan”)真的是 Android 上的同一个联系人吗?在我的手机上,有一个选项可以将联系人链接在一起,因为它们指的是同一个人,但也可以“取消链接”,这表明Android仍然保留了原来的联系人卡片,只是在两者之间建立了一个链接。也许这就是你所看到的。 是的,它们是链接的。当我从电话中获得联系人时,有些名字的电子邮件和电话都很好地关联在一起,但有些则没有。所以我认为这取决于最初如何将信息添加到联系人列表中? (你可以有来自 gmail 或其他电子邮件来源的电子邮件,你有来自 sim 的电话,或者你输入了它?)我觉得 android 有另一个地方可以保持关于同一个人的信息之间的联系。

以上是关于从安卓手机获取匹配的联系人邮箱和手机的主要内容,如果未能解决你的问题,请参考以下文章

手机邮箱Microsoft outlook安卓版更新

安卓手机怎么换联系人的头像?

安卓手机设置邮箱的办法

安卓智能手机怎样导入通信录/联系人

安卓如何将旧手机所有资料导入新手机

手机端申请企业邮箱的流程是什么?