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

Android 优化contentProvider查询以检索联系人姓名和电话,android,contacts,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.

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

    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();
        }
    }
ContentResolver ContentResolver=getContentResolver();
Cursor people=contentResolver.query(ContactsContract.Contacts.CONTENT\u URI,null,null,null);
int nameIndex=people.getColumnIndex(ContactsContract.Contacts.DISPLAY\u NAME);
int-ID=people.getColumnIndex(ContactsContract.Contacts.\u-ID);
int hasPhoneNumberIndex=people.getColumnIndex(ContactsContract.Contacts.HAS\u电话号码);
字符串名称、id;
int-hasPhoneNumber;
while(people.moveToNext()){
name=people.getString(nameIndex);
id=people.getString(idIndex);
hasPhoneNumber=people.getInt(hasPhoneNumberIndex);
如果(hasPhoneNumber>0){
游标phones=contentResolver.query(ContactsContract.commondatatypes.Phone.CONTENT\u URI,null,ContactsContract.commondatatypes.Phone.CONTACT\u ID+“=”+ID,null,null);
moveToFirst();
int phoneIndex=phones.getColumnIndex(ContactsContract.CommonDataTypes.Phone.NUMBER);
String phone=phones.getString(phoneIndex);
HashMap namePhoneType=新HashMap();
namePhoneType.put(“Name”,Name);
namePhoneType.put(“Phone”,Phone);
m_peopleList.add(namePhoneType);
电话。关闭();
}
}
但这是非常缓慢的


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

您可以阅读更多关于如何以不同方式检索姓名和电话的信息

这里有一个片段

//query for the people in your address book
Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null,People.NAME + " ASC");
startManagingCursor(cursor);

//bind the name and the number fields
String[] columns = new String[] { People.NAME, People.NUMBER };
int[] to = new int[] { R.id.name_entry, R.id.number_entry };
SimpleContactAdapter mAdapter = new SimpleContactAdapter(this, R.layout.list_entry, cursor, columns, to);
this.setListAdapter(mAdapter);

我找到了一条路:

Cursor people = getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] {Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER}, null, null,  Phone.DISPLAY_NAME + " ASC");

在我看来,指出的性能问题源于所提议的实现中固有的“n+1选择”问题

  • 打开光标以在所有联系人上迭代(1)
  • 对于每个联系人,打开一个光标以迭代该联系人的电话号码(n)
  • 如果您确实需要所有这些数据,一种更快的方法是从联系人和电话号码执行两次查询,返回相应的代理项和主键,然后在内存中执行连接

    查询1:按ContactId以地图形式获取所有联系人

    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从地图中查找联系人,并将电话号码与联系人关联

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


    发布时观察:将ID作为int获取并使用SparseArray可能是一种值得考虑的方法。但是,与此处提到的“n+1选择”问题相比,预期影响最小。

    在该帖子中说,代码仅适用于“此帖子适用于API级别4或更低级别”我已经看到了许多解决此问题的可能方案,但这是迄今为止最好的!!!我如何在一个查询中获得联系人的照片?你说的GC是什么意思?垃圾收集;您正在提取大量重复数据,这导致堆上有更多对象供垃圾收集器处理。现在这并不是一个真正的问题,因为GC已经进行了大量优化