8

我意识到这在包括 Stack Overflow 在内的各个地方都有所涉及,但我正在寻找人们可能使用过的任何其他解决方案。所以考虑到这一点...

我正在开发一个应用程序,用户最初可以在其中将他的所有联系人与桌面应用程序 OTA 同步。这是通过 Web 服务调用完成的,该调用从服务器获取一组 100 个联系人,下载并解析信息,将联系人插入 Android 联系人数据库,确认收到这些联系人,然后对下一组重复前面的步骤100 个联系人,直到同步完成。当用户在订单上有联系人或 1000-2000 时,此过程运行良好,但此应用程序的典型用户可以轻松拥有 5000-6000 联系人(高级用户超过 10000+)在这种情况下,事情需要的时间比我要长得多会的。例如,大约 5300 个联系人的样本集可能需要大约 13.5 分钟才能完成。不错,但我

我已经记录了每个步骤所需的时间,不出所料,瓶颈似乎在于将数据插入 Android 合同数据库。在网上搜索后,我发现在插入数千个联系人方面几乎没有帮助,但我发现的似乎分为以下三组:

1) ContentProviderOperation——谷歌推荐的方法,它给了我 13.5 分钟的基线,用于 5300 个联系人。

2) Bulk Inserts -- 我读到builkInsert 往往比applyBatch 更有效,但是当我尝试自己实现它时,对于相同的5300 个联系人实际上需要25 分钟。我感觉这在很大程度上是因为我需要插入 RawContact 信息,然后保存生成的 URI 以用于为 bulkInsert 创建 ContactsContract.Data,这通过 ContentProviderOperation 中的 backValueReference 更自然。此外,我查看了 android 源代码,并没有感觉到 bulkInsert 非常高效。

3) 使用 DatabaseUtils.InsertHelper 和事务创建优化的批量插入 -- 不幸的是,这似乎适合那些创建自己的内容提供程序的人,因为您需要访问底层数据库作为实例变量,我还没有看到如何这可以通过本机联系人数据库完成。

有没有人有插入 5000 多个联系人的经验或我可以考虑的任何其他可能的想法来帮助减少我的时间?还是应该将 ContentProviderOperation 视为已优化?

4

2 回答 2

0

不幸的是,我相信 1 是最好的选择。我怀疑与 iPhone 相比,您的大部分开销都在内容提供程序设计所固有的跨进程 IPC 中。

您对 3 的分析是正确的。

有根设备上有很多选项可以绕过内容提供商,但我怀疑这就是你要找的。

于 2012-11-26T23:39:42.953 回答
-1

嗨,我在几分钟内插入了大量联系人,我的代码是:

public void insertContact(contactList:List<Contact>){

  val queueSize = 300 //400
            val contactQueue = contactList.size/queueSize

            if(contactQueue > 0) {

                var startIndex = 0
                var endIndex = 0

                var tempList: List<Request.ContactBean>? = null

                totalQueue = contactQueue + 1+smsQueue

                for (i in 0..contactQueue) {

                    startIndex = i * queueSize
                    endIndex = startIndex + queueSize

                    endIndex = if (endIndex < contactList.size) endIndex else contactList.size

                    tempList = contactList.subList(startIndex, endIndex);

                    Log.d(Constant.TAG_RESTORE, "In loop totalQueue: " + contactQueue + " i: " + i
                            + " startIndex: " + startIndex + "endIndex: " + endIndex + " Queuesize: " + tempList.size)

                    restoreContact(tempList);
                }
            }else{
                totalQueue = 1+smsQueue;
                restoreContact(contactList);

            }
}





    private fun restoreContact( contactList: List<Request.ContactBean>) {



        Observable.fromCallable { insertContact(contactList); }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    totalCompleteOperation++

                    if(totalCompleteOperation === totalQueue){

                        Log.d(Constant.TAG_RESTORE, " in subscribe restoreContact " +
                                "totalCompleteOperation: "+ totalCompleteOperation +" totalQueue "+totalQueue)

                        hideDialog();
                        completeRestore(true)
                    }
                }

                )
    }



    public void insertContact(List<Request.ContactBean> contacts) throws RemoteException, OperationApplicationException {

        final int MAX_OPERATIONS_FOR_INSERTION = 100; //100
        int size = contacts.size();

            ArrayList<ContentProviderOperation> ops = new ArrayList<>();
            for (int i = 0; i < size; i++) {

                createOperations(ops, contacts.get(i));
                if (ops.size() >= MAX_OPERATIONS_FOR_INSERTION) {
                    mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
                    ops.clear();
                }
            }
            if (ops.size() > 0)
                mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); 

    }


    private void createOperations(ArrayList<ContentProviderOperation> ops,
                                                  Request.ContactBean contact){
        int backReference = ops.size();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DISABLED)
                .build()
        );
            ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                   // .withYieldAllowed(true)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backReference)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, contact.getName())
                    .build());

            if (contact.getNumbers() != null && contact.getNumbers().size() > 0) {
                // Adding insert operation to operations list
                // to insert Mobile Number in the table ContactsContract.Data
                ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                        //.withYieldAllowed(true)
                        .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backReference)
                        .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                        .withValue(Phone.NUMBER, contact.getNumbers().get(0).getNumber())
                        .withValue(Phone.TYPE, Phone.TYPE_MOBILE)
                        .build());
                if (contact.getNumbers().size() > 1) {
                    // Adding insert operation to operations list
                    // to  insert Home Phone Number in the table ContactsContract.Data
                    ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                            //.withYieldAllowed(true)
                            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backReference)
                            .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                            .withValue(Phone.NUMBER, contact.getNumbers().get(1).getNumber())
                            .withValue(Phone.TYPE, Phone.TYPE_HOME)
                            .build());
                }

            }
            if (contact.getEmails() != null && contact.getEmails().size() > 0) {
                // Adding insert operation to operations list
                // to insert Work Email in the table ContactsContract.Data
                ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                       // .withYieldAllowed(true)
                        .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backReference)
                        .withValue(ContactsContract.Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
                        .withValue(Email.ADDRESS, contact.getEmails().get(0).getAddress())
                        .withValue(Email.TYPE, Email.TYPE_WORK)
                        .build());
            }
            if (contact.getEmails().size() > 1) {
                // Adding insert operation to operations list
                // to insert Home Email in the table ContactsContract.Data
                ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                       // .withYieldAllowed(true)
                        .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backReference)
                        .withValue(ContactsContract.Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
                        .withValue(Email.ADDRESS, contact.getEmails().get(1).getAddress())
                        .withValue(Email.TYPE, Email.TYPE_HOME)
                        .build());
            }

    }

This code will insert huge contact list in very less time.
于 2018-04-05T12:37:04.350 回答