从 android 设备获取超过 10000 个联系人
Posted
技术标签:
【中文标题】从 android 设备获取超过 10000 个联系人【英文标题】:Fetching more than 10000 contacts from android device 【发布时间】:2017-05-06 11:28:45 【问题描述】:我想从 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();
【问题讨论】:
提示:只获取需要的东西而不是所有东西,这将减少查询执行时间。 我需要与联系人相关的所有号码(如他的手机、办公室、家庭)。为此,以上这些是必需的吗? 您是在使用所有联系人以显示在列表中还是用于数据存储?因为这取决于您是否使用联系人在列表中显示,然后您可以使用 load more 来一次获取包含 500 个联系人的联系人。 在这里我可以看到您正在使用_ID
、 DISPLAY_NAME
和 HAS_PHONE_NUMBER
仅来自 cur
,因此仅查询这些字段。见reference
首先,正如@RaviRupareliya 建议的那样,您应该只查询您实际需要的列。其次,您不一定确定缓慢的根源。还有其他方法调用,尚不清楚它们对性能有什么影响。如果您想获得有关如何提高代码性能的更具体建议,您应该使用 Android Studio 中的一些分析工具来衡量出现减速的位置。
【参考方案1】:
如果 1000 个联系人中有 900 个有电话号码,则您当前查询 DB 901 次,您可以将其减少到只有两个查询:
-
给我所有的联系方式
给我所有的电话号码
然后您使用两者上的contact-id
字段将手机与正确的联系人匹配。
此外,正如其他答案中所述,您确实应该在所有查询中添加 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);
【讨论】:
【参考方案2】:将您的获取过程保留在AyncTask
的doInBackground
方法中,然后显示它。并且只获取那些首先需要的信息,例如,联系人姓名和 ID。
请参阅此答案以获得更多说明: Fetching a large number of contacts
【讨论】:
就我而言,我希望所有联系人都能继续前进。所以我不能在后台加载它们。我想获取联系人并发送到服务器以及我想在列表中显示的响应。【参考方案3】:为了获取大量联系人,您必须使用 REST API 以页面形式获取联系人。 例如联系人的页面大小为 100。
一种可能的方法:
如果您在列表视图中显示联系人,那么您可以在用户滚动列表时获取数据。为此,您必须设置列表的阈值位置,即 80,因此当用户在滚动时到达第 80 位时,您可以点击下一个页面的 rest API 以获取新联系人并将这些联系人添加到列表视图中。
从您的 cmets 中,我可以看到您想要所有联系人以便继续前进。为此,您可以在启动应用程序时启动意图服务。该服务将获取所有联系人并存储它们。您可以根据需要使用它们
【讨论】:
我也经历过这个案例。但是,当我想搜索特定联系人时,此方法无济于事。如果是这样,我必须从服务器执行搜索,过程会很长。 @Sunil Subramannian 好的,您可以做的是..您可以在启动应用程序时启动意图服务。该服务将获取所有联系人并存储它们。您可以根据需要使用它们【参考方案4】:这里有一些加速优化
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);
如果可能,请在服务器端检查您的号码和长度。在异步任务中执行。
【讨论】:
添加投影有助于稍微提高性能。但不要太多......以上是关于从 android 设备获取超过 10000 个联系人的主要内容,如果未能解决你的问题,请参考以下文章
解决 Elasticsearch 超过 10000 条无法查询的问题