正在从 android 设备中获取超过 10000 个联系人
Fetching more than 10000 contacts from android device
我想从 android 设备中检索 >10000 个联系人。要获取那么多联系人,大约需要 8-10 分钟。有没有其他可能的方法来做到这一点。我已经实现了一种工作正常的方法,但是当涉及到大量联系人时,它需要时间来获取联系人。
ContentResolver cr = getActivity().getApplication().getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(
ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
int phoneType = pCur.getInt(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.TYPE));
String phoneNumber = pCur.getString(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneNumber = phoneNumber.replace(" ","");
phoneNumber = phoneNumber.replace("-","");
boolean addNumber = stringCheck(phoneNumber,symbols);
if (!addNumber){
if (phoneNumber.length() == 10){
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 11){
phoneNumber = phoneNumber.substring(1);
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 12){
phoneNumber = phoneNumber.substring(2);
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 13){
phoneNumber = phoneNumber.substring(3);
addContact(phoneNumber,phoneType,name);
}
}
}
pCur.close();
}
}
}
将您的抓取过程保留在AyncTask
的doInBackground
方法中,然后显示它。并且只获取那些首先需要的信息,例如,联系人姓名和 ID。
请参阅此 ans 以获得更多说明:
Fetching a large number of contacts
为了获取大量联系人,您必须使用 rest API 以页面形式获取联系人。
例如联系人的页面大小是 100.
一种可能的方法:
如果您在列表视图中显示联系人,那么您可以在用户滚动列表时获取数据。为此,您必须设置列表的阈值位置,即 80,因此,当用户在滚动时到达第 80 个位置时,您可以点击其余 API 进入下一页以获取新联系人并将这些联系人添加到列表视图中。
从您的评论中我可以看出您需要所有联系人才能移动forward.For这您可以在启动应用程序时启动意图服务。该服务将获取所有联系人并存储它们。您可以根据需要使用它们
此处进行了一些加速优化
String[] select = new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER};
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, select, null, null, null);
String[] selectOnly = new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.TYPE};
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
selectOnly,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
检查您的号码,如果可能的话在服务器端检查长度。在异步任务中执行。
如果 1000 个联系人中的 900 个有 phone 个号码,您当前正在查询数据库 901次,可以减少到只查询两次:
- 给我所有联系信息
- 给我所有 phone 个数字
然后您使用两者的 contact-id
字段将 phone 匹配到正确的联系人。
此外,如其他答案所述,您确实应该将 projection
添加到所有查询以提高性能。
你可以做的另一个改进是避免运行时 cur.getColumnIndex()
调用,如果你有投影,你应该已经知道索引 - 所以使用它硬编码
Map<Long, List<String>> phones = new HashMap<>();
ContentResolver cr = getActivity().getApplication().getContentResolver();
// First build a mapping: contact-id > list of phones
Cursor cur = cr.query(Phone.CONTENT_URI, new String[] { Phone.CONTACT_ID, Phone.Number }, null, null, null);
while (cur != null && cur.moveToNext()) {
long contactId = cur.getLong(0);
String phone = cur.getString(1);
List list;
if (phones.contains(contactId)) {
list = phones.get(contactId);
} else {
list = new ArrayList<String>();
phones.put(contactId, list);
}
list.add(phone);
}
cur.close();
// Next query for all contacts, and use the phones mapping
cur = cr.query(Contacts.CONTENT_URI, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1);
List<String> contactPhones = phones.get(id);
addContact(id, name, contactPhones);
}
我想从 android 设备中检索 >10000 个联系人。要获取那么多联系人,大约需要 8-10 分钟。有没有其他可能的方法来做到这一点。我已经实现了一种工作正常的方法,但是当涉及到大量联系人时,它需要时间来获取联系人。
ContentResolver cr = getActivity().getApplication().getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(
ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
int phoneType = pCur.getInt(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.TYPE));
String phoneNumber = pCur.getString(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneNumber = phoneNumber.replace(" ","");
phoneNumber = phoneNumber.replace("-","");
boolean addNumber = stringCheck(phoneNumber,symbols);
if (!addNumber){
if (phoneNumber.length() == 10){
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 11){
phoneNumber = phoneNumber.substring(1);
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 12){
phoneNumber = phoneNumber.substring(2);
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 13){
phoneNumber = phoneNumber.substring(3);
addContact(phoneNumber,phoneType,name);
}
}
}
pCur.close();
}
}
}
将您的抓取过程保留在AyncTask
的doInBackground
方法中,然后显示它。并且只获取那些首先需要的信息,例如,联系人姓名和 ID。
请参阅此 ans 以获得更多说明: Fetching a large number of contacts
为了获取大量联系人,您必须使用 rest API 以页面形式获取联系人。 例如联系人的页面大小是 100.
一种可能的方法:
如果您在列表视图中显示联系人,那么您可以在用户滚动列表时获取数据。为此,您必须设置列表的阈值位置,即 80,因此,当用户在滚动时到达第 80 个位置时,您可以点击其余 API 进入下一页以获取新联系人并将这些联系人添加到列表视图中。
从您的评论中我可以看出您需要所有联系人才能移动forward.For这您可以在启动应用程序时启动意图服务。该服务将获取所有联系人并存储它们。您可以根据需要使用它们
此处进行了一些加速优化
String[] select = new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER};
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, select, null, null, null);
String[] selectOnly = new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.TYPE};
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
selectOnly,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
检查您的号码,如果可能的话在服务器端检查长度。在异步任务中执行。
如果 1000 个联系人中的 900 个有 phone 个号码,您当前正在查询数据库 901次,可以减少到只查询两次:
- 给我所有联系信息
- 给我所有 phone 个数字
然后您使用两者的 contact-id
字段将 phone 匹配到正确的联系人。
此外,如其他答案所述,您确实应该将 projection
添加到所有查询以提高性能。
你可以做的另一个改进是避免运行时 cur.getColumnIndex()
调用,如果你有投影,你应该已经知道索引 - 所以使用它硬编码
Map<Long, List<String>> phones = new HashMap<>();
ContentResolver cr = getActivity().getApplication().getContentResolver();
// First build a mapping: contact-id > list of phones
Cursor cur = cr.query(Phone.CONTENT_URI, new String[] { Phone.CONTACT_ID, Phone.Number }, null, null, null);
while (cur != null && cur.moveToNext()) {
long contactId = cur.getLong(0);
String phone = cur.getString(1);
List list;
if (phones.contains(contactId)) {
list = phones.get(contactId);
} else {
list = new ArrayList<String>();
phones.put(contactId, list);
}
list.add(phone);
}
cur.close();
// Next query for all contacts, and use the phones mapping
cur = cr.query(Contacts.CONTENT_URI, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1);
List<String> contactPhones = phones.get(id);
addContact(id, name, contactPhones);
}