在我的项目中,获取联系人需要很长时间才能加载.
如何减少加载联系人的时间?有什么想法吗?
在编写初始方法时,我提到了以下链接.
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)
干杯...:)
总时间取决于您尝试从"联系人"表中访问的字段.访问较少的字段意味着更少的循环,更少的处理,因此更快的结果.
此外,为了加快联系人获取操作,您可以使用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)
像其他应用程序一样加载联系人.
我已经使用多个联系人测试了这个代码,它的工作正常和更快,就像其他应用程序内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
如果您的时间随着数据的增加而增加,那么您可能正在运行一个新查询来获取每个联系人的电话/电子邮件。如果您使用 查询电话/电子邮件字段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)
| 归档时间: |
|
| 查看次数: |
13753 次 |
| 最近记录: |