【问题标题】:Android: Add thousands of contacts in phonebook in bulkAndroid:在电话簿中批量添加数千个联系人
【发布时间】:2019-08-19 16:20:28
【问题描述】:

想通过 Android 中的内容提供商在电话簿中添加数千个联系人。

我已经通过以下方式实现了添加联系人:

ArrayList<ContentProviderOperation> ops = new ArrayList<>();
        int rawContactID = ops.size();

        // Adding insert operation to operations list
        // to insert a new raw contact in the table ContactsContract.RawContacts
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
                .build());

        // Adding insert operation to operations list
        // to insert display name in the table ContactsContract.Data
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getContactName())
                .build());

        // Adding insert operation to operations list
        // to insert Mobile Number in the table ContactsContract.Data
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, contact.phone)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
                .build());

        // Adding insert operation to operations list
        // to insert Home Email in the table ContactsContract.Data
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, contact.email)
                .withValue(ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.TYPE_HOME)
                .build());

        try {
            // Executing all the insert operations as a single database transaction
            contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }

每 1000 个联系人需要约 175 秒。

当我使用线程池 10 的执行器服务时,每 1000 个联系人仍然需要约 155 秒。 (效率不高)

还有其他方法可以更快地保存联系人吗?

【问题讨论】:

  • 您是否为每个原始联系人插入致电applyBatch?即,如果您要添加 1000 个联系人,您是否拨打了 1000 次 applyBatch
  • @marmor 1000 次 applyBatch()。错了吗?

标签: android performance android-contacts


【解决方案1】:

好的,你的代码的好处是你可以批量应用你的操作。 关于您的代码的不理想之处在于您的批次非常小,每个批次有 4 个操作。

您可以改为收集更大的批次(我建议每批次大约 500 个,但您可以使用这个数字。

这是一些未经测试的代码:

private static final int BATCH_SIZE = 500;

private void addThousandContacts() {
    ArrayList<ContentProviderOperation> ops = new ArrayList<>();
    for (int i = 0; i < 1000; i++) {
        addSingleContact(ops);

        if (ops.size() >= BATCH_SIZE) {
            try {
                contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
                ops.clear(); // remove all applied operations and start a new batch
            } catch (RemoteException e) {
                e.printStackTrace();
            } catch (OperationApplicationException e) {
                e.printStackTrace();
            }
        }
    }
}


private void addSingleContact(ArrayList<ContentProviderOperation> ops) {
    int rawInsertIndex = ops.size();

    // Adding insert operation to operations list
    // to insert a new raw contact in the table ContactsContract.RawContacts
    ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
            .build());

    // Adding insert operation to operations list
    // to insert display name in the table ContactsContract.Data
    ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawInsertIndex) // tells the system the index of the operation that contains the current RawContactId
            .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getContactName())
            .build());

    ... // add more operations email, phone, etc.
}

【讨论】:

  • 谢谢,伙计!有效。之前,我认为 addSingleContact 方法中的代码应该保存为原子操作。不管怎样,上面的逻辑奏效了!
  • 那么,您现在看到的性能如何? 1000 个联系人需要多少时间?
  • 大约 15 秒!快 10 倍以上 :)
  • 酷。可以通过使用批量大小来进一步改进,您可以将该 for 循环与另一个不断增加批量大小并添加另外 1000 个联系人并测量每次迭代的 for 循环包装
  • 其实applyBatch调用的ContentProviderOperations是不允许超过500个的。
猜你喜欢
  • 2017-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-02
  • 2011-10-30
  • 2014-02-07
  • 1970-01-01
相关资源
最近更新 更多