如何在Android中以最短的时间加载所有联系人

Bha*_*i D 19 android contacts

在我的项目中,获取联系人需要很长时间才能加载.

  • 有什么方法可以缩短联系时间
  • 假设我的手机中有1000个联系人.
  • 现在加载所有联系人需要2分钟以上

如何减少加载联系人的时间?有什么想法吗?

在编写初始方法时,我提到了以下链接.

http://www.coderzheaven.com/2011/06/13/get-all-details-from-contacts-in-android/

Mel*_*pes 21

更好的解决方案在这.....

private static final String[] PROJECTION = new String[] {
        ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
        ContactsContract.Contacts.DISPLAY_NAME,
        ContactsContract.CommonDataKinds.Phone.NUMBER
    };
.
.
.

ContentResolver cr = getContentResolver();
        Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);
        if (cursor != null) {
            try {
                final int nameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
                final int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);

                String name, number;
                while (cursor.moveToNext()) {
                    name = cursor.getString(nameIndex);
                    number = cursor.getString(numberIndex);
                }
            } finally {
                cursor.close();
            }
        }
Run Code Online (Sandbox Code Playgroud)

干杯...:)

  • 这是一个聪明的解决方案,但如果联系人有多个电话号码怎么办? (3认同)
  • 由于优化了查询投影,因此可以非常快速地获得结果:) (2认同)

Nap*_*ean 9

总时间取决于您尝试从"联系人"表中访问的字段.访问较少的字段意味着更少的循环,更少的处理,因此更快的结果.

此外,为了加快联系人获取操作,您可以使用ContentProvideClient,而不是每次都在ContentResolver上调用查询.这将使您查询特定的表,而不是首先查询所需的ContentProvider,然后查询表.

创建ContentProviderClient的实例

ContentResolver cResolver=context.getContextResolver();
ContentProviderClient mCProviderClient = cResolver.acquireContentProviderClient(ContactsContract.Contacts.CONTENT_URI);
Run Code Online (Sandbox Code Playgroud)

然后重用此mCProviderClient以获取呼叫中的联系人(来自任何ContentProvider的数据)数据.例如,在以下方法中,我只访问一个字段.

private ArrayList<String> fetchContactsCProviderClient()
    {
        ArrayList<String> mContactList = null;
        try
        {
            Cursor mCursor = mCProviderClient.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
            if (mCursor != null && mCursor.getCount() > 0)
            {
                mContactList = new ArrayList<String>();
                mCursor.moveToFirst();
                while (!mCursor.isLast())
                {
                    String displayName = mCursor.getString(mCursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
                    mContactList.add(displayName);
                    mCursor.moveToNext();
                }
                if (mCursor.isLast())
                {
                    String displayName = mCursor.getString(mCursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
                    mContactList.add(displayName);
                }
            }

            mCursor.close();
        }
        catch (RemoteException e)
        {
            e.printStackTrace();
            mContactList = null;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            mContactList = null;
        }

        return mContactList;
    }
Run Code Online (Sandbox Code Playgroud)


Sag*_*gar 7

像其他应用程序一样加载联系人.

我已经使用多个联系人测试了这个代码,它的工作正常和更快,就像其他应用程序内500 ms(半秒或更短)我能够加载1000+联系人.

总时间取决于您尝试从"联系人"表中访问的字段.

根据您的要求管理您的查询不要访问不需要的字段.访问较少的字段意味着更少的循环,更少的处理,因此更快的结果.

访问正确的联系表也有助于减少联系加载时间.

查询优化可以更快地加载联系人使用 projection

 String[] projection = {
            ContactsContract.Data.MIMETYPE,
            ContactsContract.Data.CONTACT_ID,
            ContactsContract.Contacts.DISPLAY_NAME,
            ContactsContract.Contacts.PHOTO_URI,
            ContactsContract.Contacts.STARRED,
            ContactsContract.RawContacts.ACCOUNT_TYPE,
            ContactsContract.CommonDataKinds.Contactables.DATA,
            ContactsContract.CommonDataKinds.Contactables.TYPE
    };
Run Code Online (Sandbox Code Playgroud)

选择和选择参数

String selection = ContactsContract.Data.MIMETYPE + " in (?, ?)" + " AND " /*+ ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + 1 + "' AND "*/ +
            ContactsContract.Data.HAS_PHONE_NUMBER + " = '" + 1 + "'";

    String[] selectionArgs = {
            ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
            ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
    };
Run Code Online (Sandbox Code Playgroud)

按字母顺序使用以下代码订购联系人

 try {
        Collections.sort(listview_address, new Comparator<ContactBook>() {
            @Override
            public int compare(ContactBook lhs, ContactBook rhs) {
                return lhs.name.toUpperCase().compareTo(rhs.name.toUpperCase());
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
Run Code Online (Sandbox Code Playgroud)

以下是完整的源代码

 public void initeContacts() {
    List<ContactBook> listview_address = new LinkedList<ContactBook>();
    SparseArray<ContactBook> addressbook_array = null;
    {
        addressbook_array = new SparseArray<ContactBook>();

        long start = System.currentTimeMillis();

        String[] projection = {
                ContactsContract.Data.MIMETYPE,
                ContactsContract.Data.CONTACT_ID,
                ContactsContract.Contacts.DISPLAY_NAME,
                ContactsContract.Contacts.PHOTO_URI,
                ContactsContract.Contacts.STARRED,
                ContactsContract.RawContacts.ACCOUNT_TYPE,
                ContactsContract.CommonDataKinds.Contactables.DATA,
                ContactsContract.CommonDataKinds.Contactables.TYPE
        };

        String selection = ContactsContract.Data.MIMETYPE + " in (?, ?)" + " AND " /*+ ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + 1 + "' AND "*/ +
                ContactsContract.Data.HAS_PHONE_NUMBER + " = '" + 1 + "'";

        String[] selectionArgs = {
                ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
                ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
        };

        String sortOrder = ContactsContract.Contacts.SORT_KEY_ALTERNATIVE;

        Uri uri = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
            uri = ContactsContract.CommonDataKinds.Contactables.CONTENT_URI;
        } else {
            uri = ContactsContract.Data.CONTENT_URI;

        }
        // we could also use Uri uri = ContactsContract.Data.CONTENT_URI;
        // we could also use Uri uri = ContactsContract.Contact.CONTENT_URI;

        Cursor cursor = getActivity().getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);


        final int mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE);
        final int idIdx = cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
        final int nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
        final int dataIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.DATA);
        final int photo = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.PHOTO_URI);
        final int typeIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.TYPE);
        final int account_type = cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE);
        while (cursor.moveToNext()) {
            int contact_id = cursor.getInt(idIdx);
            String photo_uri = cursor.getString(photo);
            String contact_name = cursor.getString(nameIdx);
            String contact_acc_type = cursor.getString(account_type);
            int contact_type = cursor.getInt(typeIdx);
            String contact_data = cursor.getString(dataIdx);
            ContactBook contactBook = addressbook_array.get(contact_id);

           /* if (contactBook == null) {
                //list  contact add to avoid duplication
                //load All contacts fro device
                //to add contacts number with name add one extra veriable in ContactBook as number and pass contact_data this give number to you (contact_data is PHONE NUMBER)
                contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "phone number");
                addressbook_array.put(contact_id, contactBook);
                listview_address.add(contactBook);

            }*/

            String Contact_mimeType = cursor.getString(mimeTypeIdx);
            //here am checking Contact_mimeType to get mobile number asociated with perticular contact and email adderess asociated
            if (Contact_mimeType.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {

                if (contactBook != null) {
                    contactBook.addEmail(contact_type, contact_data);
                }

            } else {
                if (contactBook == null) {
                    //list  contact add to avoid duplication
                    //load All contacts fro device
                    //to add contacts number with name add one extra veriable in ContactBook as number and pass contact_data this give number to you (contact_data is PHONE NUMBER)
                    contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "phone number");
                    addressbook_array.put(contact_id, contactBook);
                    listview_address.add(contactBook);

                }
               // contactBook.addPhone(contact_type, contact_data);


            }


        }

        cursor.close();


        try {
            Collections.sort(listview_address, new Comparator<ContactBook>() {
                @Override
                public int compare(ContactBook lhs, ContactBook rhs) {
                    return lhs.name.toUpperCase().compareTo(rhs.name.toUpperCase());
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
Run Code Online (Sandbox Code Playgroud)

您可以在我评论的上述代码中使用以下代码.它将单个联系人与其多个号码联系起来.在Object类中获取与单个联系人使用数组相关联的所有数字.

 if (contactBook == null) {
            //irst  contact add to avoid duplication
            //load All contacts fro device
            contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "");
            addressbook_array.put(contact_id, contactBook);
            listview_address.add(contactBook);
        }

        String Contact_mimeType = cursor.getString(mimeTypeIdx);
        //here am checking Contact_mimeType to get mobile number asociated with perticular contact and email adderess asociated
        if (Contact_mimeType.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {

            contactBook.addEmail(contact_type, contact_data);

        } else {

            contactBook.addPhone(contact_type, contact_data);

        }
Run Code Online (Sandbox Code Playgroud)

对象类

public class ContactBook {
public int id;
public Resources res;
public String name;
public String photo;
public String contact_acc_type;
public SparseArray<String> emails;
public SparseArray<String> phones;
/*  public LongSparseArray<String> emails;
public LongSparseArray<String> phones;*/
public String header = "";


public ContactBook(int id, String name, Resources res, String photo, String contact_acc_type, String header) {
    this.id = id;
    this.name = name;
    this.res = res;
    this.photo = photo;
    this.contact_acc_type = contact_acc_type;
    this.header = header;
}

@Override
public String toString() {
    return toString(false);
}

public String toString(boolean rich) {

    //testing method to check ddata
    SpannableStringBuilder builder = new SpannableStringBuilder();
    if (rich) {
        builder.append("id: ").append(Long.toString(id))
                .append(", name: ").append("\u001b[1m").append(name).append("\u001b[0m");
    } else {
        builder.append(name);
    }

    if (phones != null) {
        builder.append("\n\tphones: ");
        for (int i = 0; i < phones.size(); i++) {
            int type = (int) phones.keyAt(i);
            builder.append(ContactsContract.CommonDataKinds.Phone.getTypeLabel(res, type, ""))
                    .append(": ")
                    .append(phones.valueAt(i));
            if (i + 1 < phones.size()) {
                builder.append(", ");
            }
        }
    }

    if (emails != null) {
        builder.append("\n\temails: ");
        for (int i = 0; i < emails.size(); i++) {
            int type = (int) emails.keyAt(i);
            builder.append(ContactsContract.CommonDataKinds.Email.getTypeLabel(res, type, ""))
                    .append(": ")
                    .append(emails.valueAt(i));
            if (i + 1 < emails.size()) {
                builder.append(", ");
            }
        }
    }
    return builder.toString();
}

public void addEmail(int type, String address) {
    //this is the array in object class where i am storing contact all emails of perticular contact (single)
    if (emails == null) {
        //   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        emails = new SparseArray<String>();
        emails.put(type, address);
        /*} else {
            //add emails to array below Jelly bean //use single array list
        }*/
    }
}

public void addPhone(int type, String number) {
    //this is the array in object class where i am storing contact numbers of perticular contact
    if (phones == null) {
        //  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        phones = new SparseArray<String>();
        phones.put(type, number);
       /* } else {
            //add emails to array below Jelly bean //use single array list
        }*/
    }
}}
Run Code Online (Sandbox Code Playgroud)


小智 5

为了以最短的时间加载联系人,最佳解决方案是在查询光标的联系人时使用投影和选择参数的概念。

这可以通过以下方式完成

void getAllContacts() {
    long startnow;
    long endnow;

    startnow = android.os.SystemClock.uptimeMillis();
    ArrayList arrContacts = new ArrayList();

    Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER;
    Cursor cursor = ctx.getContentResolver().query(uri, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER,   ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.Contacts._ID}, selection, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");

    cursor.moveToFirst();
    while (cursor.isAfterLast() == false) {

        String contactNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
        String contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
        int phoneContactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID));
        int contactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
        Log.d("con ", "name " + contactName + " " + " PhoeContactID " + phoneContactID + "  ContactID " + contactID)

        cursor.moveToNext();
    }
    cursor.close();
    cursor = null;

    endnow = android.os.SystemClock.uptimeMillis();
    Log.d("END", "TimeForContacts " + (endnow - startnow) + " ms");
}
Run Code Online (Sandbox Code Playgroud)

使用上述方法,加载触点需要 400 毫秒(不到一秒),而正常情况下需要 10-12 秒。

有关详细信息,这篇文章可能会有所帮助,因为我从中获得了帮助 http://www.blazin.in/2016/02/loading-contacts-fast-from-android.html


Ang*_*qui 5

如果您的时间随着数据的增加而增加,那么您可能正在运行一个新查询来获取每个联系人的电话/电子邮件。如果您使用 查询电话/电子邮件字段ContactsContract.CommonDataKinds.Phone.NUMBER,那么您将仅检索每个联系人 1 部电话。解决方案是投影字段并通过联系人 ID 将它们连接起来。

这是我在 Kotlin 中的解决方案(提取 ID、姓名、所有电话和电子邮件):

val projection = arrayOf(
        ContactsContract.Data.MIMETYPE,
        ContactsContract.Data.CONTACT_ID,
        ContactsContract.Contacts.DISPLAY_NAME,
        ContactsContract.CommonDataKinds.Contactables.DATA

)
val selection = "${ContactsContract.Data.MIMETYPE} in (?, ?)"

val selectionArgs = arrayOf(
        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

val contacts = applicationContext
        .contentResolver
        .query(ContactsContract.Data.CONTENT_URI, projection, selection, selectionArgs, null)
        .run {
            if (this == null) {
                throw IllegalStateException("Cursor null")
            }
            val contactsById = mutableMapOf<String, LocalContact>()
            val mimeTypeField = getColumnIndex(ContactsContract.Data.MIMETYPE)
            val idField = getColumnIndex(ContactsContract.Data.CONTACT_ID)
            val nameField = getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
            val dataField = getColumnIndex(ContactsContract.CommonDataKinds.Contactables.DATA)

            while (moveToNext()) {
                val mimeType = getString(mimeTypeField)
                val id = getString(idField)
                var contact = contactsById[id]
                if (contact == null) {
                    val name = getString(nameField)
                    contact = LocalContact(id = id, fullName = name, phoneNumbers = listOf(), emailAddresses = listOf())
                }
                val data = getString(dataField)
                when(getString(mimeTypeField)) {
                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ->
                        contact = contact.copy(emailAddresses = contact.emailAddresses + data)
                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ->
                        contact = contact.copy(phoneNumbers = contact.phoneNumbers + data)
                }
                contactsById[id] = contact
            }
            close()
            contactsById.values.toList()
        }
Run Code Online (Sandbox Code Playgroud)

作为参考,我的LocalContact模型:

data class LocalContact(
        val id: String,
        val fullName: String?,
        val phoneNumbers: List<String>,
        val emailAddresses: List<String>
)
Run Code Online (Sandbox Code Playgroud)