Telephony.Sms.Inbox.PERSON 使用已弃用的 Contacts.People._ID

Posted

技术标签:

【中文标题】Telephony.Sms.Inbox.PERSON 使用已弃用的 Contacts.People._ID【英文标题】:Telephony.Sms.Inbox.PERSON uses deprecated Contacts.People._ID 【发布时间】:2017-05-20 14:05:32 【问题描述】:

赏金奖 - 赏金将颁发给仅使用ContractsContact 表从填充的Telephony.Sms.Inbox.PERSON 值到关联的Contact 的答案。


我正在我的应用程序中以标准方式阅读 SMS 消息:

    final String[] projection = Telephony.Sms.Inbox.BODY,
            Telephony.Sms.Inbox.ADDRESS,
            Telephony.Sms.Inbox.READ,
            Telephony.Sms.Inbox.DATE,
            Telephony.Sms.Inbox.PERSON;

    final Cursor cursor = ctx.getContentResolver().query(Telephony.Sms.Inbox.CONTENT_URI,
            projection, null, null, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER);

填充后,从索引 Telephony.Sms.Inbox.PERSON 返回的 id 与已弃用的 Contacts.People._ID 的 id 相关,可用于通过以下方式查询更多联系信息:

    final String[] projection = Contacts.People.DISPLAY_NAME;
    final String[] selectionArgs = contactId;

    final Cursor cursor = ctx.getContentResolver().query(Contacts.People.CONTENT_URI,
            projection, Contacts.People._ID + " = ?", selectionArgs, null);

为什么相对较新的Telephony API 会使用deprecated tables,而不是ContactsContract?

Telephony.Sms.Inbox.PERSON 文档状态:

类型:INTEGER(引用 content://contacts/people 中的项目)

我尝试在任何 ContactsContract id 字段中查找到 id 的映射,但没有成功(但并不奇怪?),因此我不得不使用已弃用的 API 来解决我需要的查询快速执行。

此类查询包括搜索特定联系人的消息,我只知道该联系人的姓名。联系人可能有多个号码,其格式可能与Telephony.Sms.Inbox.ADDRESS 条目不匹配.....

使用Telephony.Sms.Inbox.ADDRESS 和ContactsContract.PhoneLookup 的workaround 不是从号码到联系人的世界末日,但我仍然觉得我一定在这里错过了什么

这是我用来获取“Joe Bloggs”消息的过程。

1) 查询ContactsContract 表以确认设备上存在名为 Joe Bloggs 的联系人 - 如果联系人实际上被列为“Joe Blogs”,则获得密切匹配。

2) 使用确认的名称,我查询已弃用的Contact.People 表,以通过以下方式获取联系人的所有关联 ID:

    final String selection = Contacts.People.DISPLAY_NAME + " LIKE ?";

    final String[] projection = Contacts.People.DISPLAY_NAME,
            Contacts.People._ID;

    final String[] selectionArgs = contactName;

    final Cursor cursor = ctx.getContentResolver().query(Contacts.People.CONTENT_URI,
            projection, selection, selectionArgs, null);

3) 使用已弃用的联系人 ID 列表,我查询消息表如下:

    final String[] referredArgs = new String[contactIdArray.size()];
    for (int i = 0; i < contactIdArray.size(); i++) 
        referredArgs[i] = contactIdArray.get(i);
    

    final String referredSelection = Telephony.Sms.Inbox.PERSON + " IN "
            + "(" + TextUtils.join(",", referredArgs) + ")";

    final String[] projection = Telephony.Sms.Inbox.BODY,
            Telephony.Sms.Inbox.ADDRESS,
            Telephony.Sms.Inbox.READ,
            Telephony.Sms.Inbox.DATE,
            Telephony.Sms.Inbox.PERSON;

    final Cursor cursor = ctx.getContentResolver().query(Telephony.Sms.Inbox.CONTENT_URI,
            projection, referredSelection, null, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER);

我希望有人会告诉我,我正在到处转转,使用当前的 API 有一个更明显的解决方案。 我不考虑使用 ContactsContract.PhoneLookup 迭代整个消息表优化的解决方案。

提前致谢。

【问题讨论】:

【参考方案1】:

如果我是你,我不会使用Telephony.Sms.Inbox.PERSON 字段,也绝对不会查询已弃用的People api。 People api 已经被弃用了很长时间,你不能指望我们那里的所有设备都能够正确地支持它。

您需要了解的第一件事是短信和联系人之间没有一对一的链接。 SMS 可以来自非联系人电话号码、单个联系人、多个联系人、联系人和非联系人的混合、字母数字 ID,甚至其他更罕见的选项。

接下来,您应该仔细阅读股票代码以及它如何处理您可以从 SMS 集合中获得的正确称为“收件人 ID”的集合,有一个名为 canonical-addresses(或 canonical-address)的集合用作电话号码(或以逗号分隔的电话列表)和收件人 ID 之间的映射。 该代码在启动时执行单个查询以将整个表缓存在内存中,然后使用它在电话和收件人 ID 之间进行映射。

这是mapping class

【讨论】:

感谢您的回答 - 我很感激 there isn't a one-to-one link between sms and contacts,但是在收到短信/彩信后某处“创建”了一个,这导致填充了“id/ids”。从您的链接中,我试图在 android 源代码中从地址中找到此映射发生的位置,但没有任何乐趣。我想知道现在是否由默认的短信/彩信提供商来实现这一点?请问您有这方面的经验吗? 我想我可能已经找到它here。它建议它使用ContactsContract.CommonDataKinds.Phone?我发誓我已经检查过这个 id 不匹配。 @brandall 一个联系人可以删除/创建/更改,并且可以有多个不同的联系人具有相同的号码,短信数据库跟不上联系人数据库的变化,唯一的事情无法更改的是发送/接收该短信的规范地址,这就是为什么 RecipientId 必须映射到电话而不是联系人的原因。其余的是,如在 mms.data.Contact.java 中实现的,由实现者在规范地址和联系人之间进行映射 我听到了,但系统会在某处创建规范地址和 Person 之间的映射,只要有可能。这就是我所追求的,因为当我找到它时,我可以扭转这个过程。 Phone id 与上面的评论不匹配,Contacts id 引用自 here 也不匹配。我目前正在对“ContactsContract”中引用的所有 id 字段重新运行查询,以确保我没有第一次忽略一个。【参考方案2】:

为什么相对较新的 Telephony API 会使用已弃用的表,而不是 ContactsContract?

你指的是不是新的。在Telephony.java 中,您会看到它依赖于现有的content://sms 提供程序:

    public static final class Inbox implements BaseColumns, TextBasedSmsColumns 
        /**
         * The @code content:// style URL for this table.
         */
        public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox");

它已经是there in Donut(可能之前,但我没有检查)。

Kitkat is the ability to change the SMS app 的新功能。

【讨论】:

【参考方案3】:

我没有正确理解您的担忧,但我正在从事类似的项目,这里是基本代码,以及用于获取和显示消息的基本重要列:

ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]"*";

Cursor SMSL = contentResolver.query(Telephony.Sms.CONTENT_URI, projection, null, null, "date ASC");
int msgscount = SMSL.getCount();

if (msgscount>0) 
msgs = new String[SMSL.getCount()][msgs_column_count];
    int i = 0;
    while (SMSL.moveToNext()) 
        progress.setProgress(i);

        msgs[i][0] = SMSL.getString(SMSL.getColumnIndex("address"));
        msgs[i][1] = SMSL.getString(SMSL.getColumnIndex("date_sent"));
        msgs[i][2] = SMSL.getString(SMSL.getColumnIndex("date"));
        msgs[i][3] = SMSL.getString(SMSL.getColumnIndex("type"));
        msgs[i][4] = SMSL.getString(SMSL.getColumnIndex("body"));
        msgs[i][5] = SMSL.getString(SMSL.getColumnIndex("read"));
        if (SMSL.getString(SMSL.getColumnIndex("service_center")) != null)
            msgs[i][6] = SMSL.getString(SMSL.getColumnIndex("service_center"));
        else
            msgs[i][6] = "";
        
                    i++;
    
    SMSL.close();
else
     msgs = new String[0][0];
     Toast.makeText(getApplicationContext(),"No messages found!",Toast.LENGTH_LONG).show();

如果您在这方面需要任何帮助或获取消息,请告诉我。

【讨论】:

问题是问为什么PERSON 的返回值与已弃用的Contacts.People id 相关,而不是使用ContactsContract 表中的值。查询消息表不是问题。

以上是关于Telephony.Sms.Inbox.PERSON 使用已弃用的 Contacts.People._ID的主要内容,如果未能解决你的问题,请参考以下文章