android - 优化 contentProvider 查询以检索联系人姓名和电话

标签 android contacts android-contentprovider

目前,我使用此代码来获取联系人姓名和电话号码:

    ContentResolver contentResolver = getContentResolver();

    Cursor people = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

    int nameIndex = people.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
    int idIndex = people.getColumnIndex(ContactsContract.Contacts._ID);
    int hasPhoneNumberIndex = people.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);

    String name, id;
    int hasPhoneNumber;

    while(people.moveToNext()){
        name = people.getString(nameIndex);
        id = people.getString(idIndex);
        hasPhoneNumber = people.getInt(hasPhoneNumberIndex);

        if(hasPhoneNumber > 0){
            Cursor phones = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+id, null, null);
            phones.moveToFirst();

            int phoneIndex = phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
            String phone = phones.getString(phoneIndex);

            HashMap<String, String> namePhoneType = new HashMap<String, String>();
            namePhoneType.put("Name", name);
            namePhoneType.put("Phone", phone);

            m_peopleList.add(namePhoneType);

            phones.close();
        }
    }

但这非常慢。

是否有一种方法可以仅在一次查询中检索姓名和电话?

最佳答案

在我看来,所提到的性能问题源于所提出的实现中固有的“n+1 select”问题。

  1. 打开游标以迭代所有联系人 (1)
  2. 对于每个联系人,打开一个光标以迭代该联系人的电话号码 (n)

如果您确实需要所有这些数据,一种更快的方法是从联系人和电话号码执行两个查询,返回适当的代理键和主键,然后在内存中执行联接。

查询1:通过ContactId获取所有联系人作为 map

With the myriad of solutions proposed being sure to pull out the _ID field as the ContactId

查询2:获取所有电话号码并将它们存储在列表中

        Cursor c = MyO2Application.getContext().getContentResolver().query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                new String[] {
                        ContactsContract.CommonDataKinds.Phone._ID,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                        ContactsContract.CommonDataKinds.Phone.NUMBER },
                null,
                null,
                null
        );
        while (c.moveToNext()) {
            String id = c.getString(0);
            String contactId = c.getString(1);  // this is the foreign key to the contact primary key
            String displayName = c.getString(2);
            String number = c.getString(3);

然后,您可以遍历电话号码列表,通过 ContactId 从 map 中查找联系人,并将电话号码与联系人相关联。

1000 个联系人的执行速度从 60 秒降至 4 秒。通常情况下,需要在内存消耗和对 GC 的影响之间进行权衡。

发布时的观察:将 ids 作为 int 获取并使用 SparseArray 可能是一种值得考虑的方法。然而,与此处解决的“n+1 选择”问题相比,预计影响很小。

关于android - 优化 contentProvider 查询以检索联系人姓名和电话,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7520635/

相关文章:

Android线程问题

android - 如果我安装了 Facebook 应用程序,我的 Facebook 登录 Android 应用程序将不会打开 session

java - 堆积条形图 : Changing appearance of entire bar?

android - 在 Android 中查询 Google Play 音乐数据库

java - 国家、州和城市微调器无法正常工作

Android:表sql查询错误

java - 让用户创建业务或个人联系人的代码

ruby - 使用 omnicontacts gem 在 ruby​​ 脚本中获取雅虎联系人

Android - 选取图像时无法使用相同的 URI 两次

android - URIMatcher 不匹配