【问题标题】:Search contacts provider for phone numbers in multiple formats?在联系人提供商中搜索多种格式的电话号码?
【发布时间】:2016-04-27 03:14:41
【问题描述】:

我一直在编写一段代码,让用户可以按姓名、电子邮件或电话号码搜索(使用 AutoCompleteTextView 逐个字符)联系人。我已经制定了以下代码:

// General contact data, so we have to get the DATA1 attribute and use MIMETYPE
                    // to figure out what it is. Usually we'd query, say, ContactsContract.CommonDataKinds.Email.CONTENT_URI
                    Uri uri = ContactsContract.Data.CONTENT_URI;
                    // Limit the query results to only the columns we need for faster operations.
                    // Using a projection also seems to make the query DISTINCT
                    String[] projection    = new String[] {ContactsContract.Contacts.DISPLAY_NAME,
                            ContactsContract.Data.DATA1,
                            ContactsContract.Data.MIMETYPE};
                    // Find contact records with an email address or phone number
                    // Search the name and data1 field (which may contain an email or phone number)
                    // for user-entered search phrase
                    String filter = "(" + ContactsContract.Data.MIMETYPE + "=? OR " + ContactsContract.Data.MIMETYPE + "=?)"
                            + " AND (" + ContactsContract.Data.DATA1 + " LIKE ? OR " + ContactsContract.Data.DISPLAY_NAME + " LIKE ?)";
                    String wildcardedConstraint = "%" + constraintString + "%";
                    String[] filterParams = new String[]{ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE, wildcardedConstraint, wildcardedConstraint};
                    // Sort contacts with the most recently contacted ones first. That's often 0 (unset)
                    // so do a sub-sort by last updated date, most recent contacts first
                    String orderBy = ContactsContract.Contacts.LAST_TIME_CONTACTED + " DESC, " + ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " DESC";
                    Cursor cursor = getContext().getContentResolver().query(uri, projection, filter, filterParams, orderBy);
                    if (cursor != null) {
                        while (cursor.moveToNext()) {
                            String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
                            String data1 = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DATA1));
                            String mimetype = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.MIMETYPE));
                            String number = null;
                            String email = null;
                            if (mimetype.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
                                email = data1;
                            } else if (mimetype.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
                                number = data1;
                            }

                            items.add(new Person(name, number, email));

                            Log.e("temp", name + " " + data1 + " " + mimetype);
                        }

                        cursor.close();
                    }

但是,电话号码搜索存在问题。在通讯录中,电话号码有多种不同的格式:

  • +101234567890
  • (123) 456-7890
  • 1234567890
  • 123-456-7890

等等。

如何调整我的联系人查询过滤器,以便用户的输入可以找到任何格式的电话号码 - 最好不要让整个查询变得非常慢?

我发现的一些解决方案依赖于编辑表格数据来标准化电话号码,这不是联系人的选项。也许规范化的数字字段会起作用......如果我能找到一种方法来轻松地将它构建到联系人数据表上的这个查询中。我知道我可以对每条记录进行额外的电话号码搜索,或者使用 Java 进行检查,但我认为这会使其非常慢。可能是查询中的正则表达式 SQL 运算符——但我不知道如何使它适用于用户可能只输入部分电话号码的逐字符搜索。

有什么想法吗?

【问题讨论】:

  • 不是重复的。另一个问题是关于如何对电话号码进行基本搜索。上面的代码已经成功地通过姓名、电子邮件地址或电话号码进行了更高级的搜索。问的问题是当联系人中的电话号码是多种格式时如何进行搜索,这是其他问题甚至没有考虑的问题。
  • 这就是PhoneLookup 表的用途;匹配不同格式的数字。注意它提到来电显示的地方。如果您不想使用它,请使用 PhoneNumberUtils.compare() 手动过滤当前数据集。
  • 等一下。我只是想到了另一种方法,你可以用现有的查询来做到这一点。让我做一些测试。

标签: android


【解决方案1】:

您可以使用 Android 的内置 SQLite 函数 PHONE_NUMBERS_EQUAL 来执行此操作,该函数比较两个数字,如果它们对于来电显示目的足够相同,则返回 1

您只需按如下方式更改您的filter

String filter = "(" + ContactsContract.Data.MIMETYPE + "=? OR "
    + ContactsContract.Data.MIMETYPE + "=?) AND "
    + "(PHONE_NUMBERS_EQUAL(" + ContactsContract.Data.DATA1 + ", ?, 0) OR "
    + ContactsContract.Data.DATA1 + " LIKE ? OR "
    + ContactsContract.Data.DISPLAY_NAME + " LIKE ?)";

然后将另一个wildcardedConstraint 添加到您的filterParams

String[] filterParams = new String[] { ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
                                       ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
                                       wildcardedConstraint,
                                       wildcardedConstraint,
                                       wildcardedConstraint };

PHONE_NUMBERS_EQUAL函数中最后的INTEGER参数表示是否使用严格数比较; 1 表示使用严格,0 表示非严格。显然这是一个系统范围的设置,可以从系统Resources 中检索到,但我不确定哪些因素决定了如何针对特定环境确定此设置。上面的例子只是使用了非严格比较。但是,如果它是一个问题,则可以像这样获得实际的资源值:

private static final String STRICT_COMPARE = "config_use_strict_phone_number_comparation";

...

int strictResId = Resources.getSystem().getIdentifier(STRICT_COMPARE, "bool", "android");
boolean useStrict = Resources.getSystem().getBoolean(strictResId);

【讨论】:

  • 糟糕。坚持,稍等。我刚刚意识到我的查询不正确。给我一分钟解决它。
  • 好的,我认为这与你对原版所做的一致。
  • 哇,多么酷的功能!我不知道那件事。我也很欣赏详细的代码示例!但有两个问题:一,它实际上似乎不起作用?二,我猜它只会比较确切的电话号码 - 所以在逐个字符输入时它会失败,至少在输入整个号码之前(在这种情况下不需要自动完成)?
  • 没有汗水。是的,不久前我在挖掘 MMS/SMS Provider 源时遇到了这个功能。在我提到PhoneNumberUtils.compare() 方法之前,我已经忘记了它。希望它对你有用。干杯!
  • 好吧,我现在有一个查询部分使用AutoCompleteTextView。不得不采用更多的蛮力方法。如您所知,PHONE_NUMBERS_EQUAL 不能用于此,如果我仔细阅读了您的问题并注意到您使用的是AutoCompleteTextView,我可能什至都​​不会提到它。无论如何,我仍然需要找出为什么我会得到一些错误的匹配,但我最终应该有一些可行的东西。
猜你喜欢
  • 2011-04-12
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
  • 2014-11-01
  • 2014-03-30
  • 1970-01-01
  • 2013-10-10
相关资源
最近更新 更多