如何在一个SQLite查询中获取联系人ID,电子邮件,电话号码? 联系人Android优化

我希望至少使用一个电话号码获取所有联系人,我也想要每个联系人的所有电话号码和所有电子邮件。

当前代码:

// To get All Contacts having atleast one phone number. Uri uri = ContactsContract.Contacts.CONTENT_URI; String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " > ?"; String[] selectionArgs = new String[] {"0"}; Cursor cu = applicationContext.getContentResolver().query(uri, null, selection, selectionArgs, null); // For getting All Phone Numbers and Emails further queries : while(cu.moveToNext()){ String id = cu.getString(cu.getColumnIndex(ContactsContract.Contacts._ID)); // To get Phone Numbers of Contact Cursor pCur = context.getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?", new String[]{id}, null); // To get Email ids of Contact Cursor emailCur = context.getContentResolver().query( ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{id}, null); // Iterate through these cursors to get Phone numbers and Emails } 

如果我的设备中有超过1000个联系人,则需要花费太多时间。 如何在单个查询中获取所有数据,而不是为每个联系人执行另外两个查询?

或者还有其他方法可以优化吗?

先谢谢你。

  • android sqlite CREATE TABLE IF NOT NOT EXISTS
  • Android:使用ContentResolver时的SQLite事务
  • 在SimpleCursorAdapter中使用哪个标志?
  • 查询SQLite For Android中列的最大值
  • Android的SQLite - select字段为空或空的logging
  • 我怎样才能得到有关列在android sqlite中引起外键约束的信息?
  • Android ContentProvider性能
  • 如何在android上的Query中添加WHERE子句
  • ICS:当您从Data.CONTENT_URI查询时,您已经加入了关联Contact所有行 – 即这将起作用:

     ContentResolver resolver = getContentResolver(); Cursor c = resolver.query( Data.CONTENT_URI, null, Data.HAS_PHONE_NUMBER + "!=0 AND (" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?)", new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE}, Data.CONTACT_ID); while (c.moveToNext()) { long id = c.getLong(c.getColumnIndex(Data.CONTACT_ID)); String name = c.getString(c.getColumnIndex(Data.DISPLAY_NAME)); String data1 = c.getString(c.getColumnIndex(Data.DATA1)); System.out.println(id + ", name=" + name + ", data1=" + data1); } 

    如果您的目标是2.3,则需要考虑通过查询Data时使用的连接无法使用HAS_PHONE_NUMBER这一事实。

    好玩

    例如,可以通过跳过您的联系人必须拥有电话号码的要求来解决这个问题,而不是满足于“与至少一个电话号码或电子邮件地址的任何联系”:

     Cursor c = resolver.query( Data.CONTENT_URI, null, Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?", new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE}, Data.CONTACT_ID); 

    如果这不是一个选项,你总是可以选择一个可怕的hacky子选项:

     Cursor c = resolver.query( Data.CONTENT_URI, null, "(" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?) AND " + Data.CONTACT_ID + " IN (SELECT " + Contacts._ID + " FROM contacts WHERE " + Contacts.HAS_PHONE_NUMBER + "!=0)", new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE}, Data.CONTACT_ID); 

    或者使用两个 Cursor来解决它:

     Cursor contacts = resolver.query(Contacts.CONTENT_URI, null, Contacts.HAS_PHONE_NUMBER + " != 0", null, Contacts._ID + " ASC"); Cursor data = resolver.query(Data.CONTENT_URI, null, Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?", new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE}, Data.CONTACT_ID + " ASC"); int idIndex = contacts.getColumnIndexOrThrow(Contacts._ID); int nameIndex = contacts.getColumnIndexOrThrow(Contacts.DISPLAY_NAME); int cidIndex = data.getColumnIndexOrThrow(Data.CONTACT_ID); int data1Index = data.getColumnIndexOrThrow(Data.DATA1); boolean hasData = data.moveToNext(); while (contacts.moveToNext()) { long id = contacts.getLong(idIndex); System.out.println("Contact(" + id + "): " + contacts.getString(nameIndex)); if (hasData) { long cid = data.getLong(cidIndex); while (cid < = id && hasData) { if (cid == id) { System.out.println("\t(" + cid + "/" + id + ").data1:" + data.getString(data1Index)); } hasData = data.moveToNext(); if (hasData) { cid = data.getLong(cidIndex); } } } } 

    我经历了完全相同的问题。 从那时起,我构建了自己的解决方案,这个解决方案的灵感来自这篇文 现在我想分享它作为我的第一个StackOverFlow答案:-)

    它与Jens建议的双光标方法非常相似。 这个想法是为了

    1-从“联系人”表中获取相关联系人
    2-获取相关联系人信息(邮件,电话……)
    3-结合这些结果

    “相关”当然取决于你,但重要的是表现! 此外,我确信使用非常适合的SQL查询的其他解决方案也可以完成这项工作,但在这里我只想使用Android ContentProvider这是代码:

    一些常数

     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; 

    1联系

    在这里,我要求联系人必须让DISPLAY_NAME免于“@”并且他们的信息与给定字符串匹配(当然可以修改这些要求)。 以下方法的结果是第一个游标:

     public Cursor getContactCursor(String stringQuery, String sortOrder) { Logger.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++"); Logger.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 = sContext.getContentResolver().query(CONTENT_URI, PROJECTION, SELECTION, SELECTION_ARGS, sortOrder); Long t1 = System.currentTimeMillis(); Logger.e(TAG, "ContactCursor finished in " + (t1 - t0) / 1000 + " secs"); Logger.e(TAG, "ContactCursor found " + cursor.getCount() + " contacts"); Logger.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++"); return cursor; } 

    你会看到这个查询非常高效!

    2联系方式

    现在让我们获取联系信息。 在这一点上,我没有在已经获取的联系人和检索到的信息之间建立任何联系:我只是从数据表中获取所有信息…但是,为了避免无用的信息,我仍然需要DISPLAY_NAMES免于“@”,因为我’我对电子邮件和手机感兴趣我要求数据MIMETYPE为MAIL_TYPE或PHONE_TYPE(请参阅常量)。 这是代码:

     public Cursor getContactDetailsCursor() { Logger.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++"); Logger.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 = ContactManager.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 = sContext.getContentResolver().query( ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, SELECTION_ARGS, null); Long t1 = System.currentTimeMillis(); Logger.e(TAG, "ContactDetailsCursor finished in " + (t1 - t0) / 1000 + " secs"); Logger.e(TAG, "ContactDetailsCursor found " + cursor.getCount() + " contacts"); Logger.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++"); return cursor; } 

    你会再次看到这个查询非常快……

    3结合

    现在让我们结合联系人和他们各自的信息。 我们的想法是使用HashMap(Key,String),其中Key是Contact id,String是你喜欢的(name,email,…)。

    首先,我运行Contact游标(按字母顺序排列)并在两个不同的HashMap中存储名称和图片uri。 另请注意,我将所有联系人ID存储在列表中,其顺序与联系人在游标中出现的顺序相同。 让我们调用这个列表contactListId

    我对联系信息(邮件和电子邮件)也这样做。 但是现在我处理两个光标之间的相关性:如果电子邮件或电话的CONTACT_ID没有出现在contactListId中,它就被放在一边。 我还检查是否已经遇到电子邮件。 请注意,此进一步选择可能会在名称/图片内容和电子邮件/电话HashMap内容之间引入不对称,但不要担心。

    最后,我遍历contactListId列表并构建一个Contact对象列表,其中包含以下事实:联系人必须具有信息(keySet条件),并且联系人必须至少包含邮件或电子邮件(mail =的情况=如果联系人是Skype联系人,则可能会出现= null && phone == null)。 这是代码:

     public List 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); List contactIds = new ArrayList<>(); if (contactCursor.moveToFirst()) { do { contactIds.add(contactCursor.getInt(contactCursor.getColumnIndex(CONTACT_ID_URI))); } while (contactCursor.moveToNext()); } HashMap nameMap = new HashMap<>(); HashMap 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 emailMap = new HashMap<>(); HashMap 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 contacts = new ArrayList<>(); Set detailsKeySet = emailMap.keySet(); for (Integer key : contactIds) { if(!detailsKeySet.contains(key) || (emailMap.get(key) == null && phoneMap.get(key) == null)) continue; contacts.add(new Contact(String.valueOf(key), pictureMap.get(key), nameMap.get(key), emailMap.get(key), phoneMap.get(key))); } return contacts; } 

    Contact对象定义取决于您。

    希望这将有助于并感谢上一篇文章。

    校正/改进

    我忘记检查手机按键了:它应该看起来像

     !mailKeySet.contains(key) 

    取而代之

      (!mailKeySet.contains(key) && !phoneKeySet.contains(key)) 

    用手机键设置

     Set phoneKeySet = phoneMap.keySet(); 

    我为什么不添加一个空的联系人光标检查,如:

     if(contactCursor.getCount() == 0){ contactCursor.close(); return new ArrayList<>(); } 

    在getContactCursor调用之后