Android 插入5000+;安卓联系人

Android 插入5000+;安卓联系人,android,contacts,Android,Contacts,我意识到这在很多地方都有所涉及,包括堆栈溢出,但我正在寻找人们可能使用的任何其他解决方案。所以考虑到这一点 我正在开发一个应用程序,用户可以首先将所有联系人与桌面应用程序同步。这是通过web服务调用完成的,该调用从服务器获取一组100个联系人,下载并解析信息,将联系人插入Android联系人数据库,确认收到这些联系人,然后对下一组100个联系人重复前面的步骤,直到同步完成。当用户拥有订单上的联系人或1000-2000个联系人时,此过程非常有效,但此应用程序的典型用户可以轻松拥有5000-6000

我意识到这在很多地方都有所涉及,包括堆栈溢出,但我正在寻找人们可能使用的任何其他解决方案。所以考虑到这一点

我正在开发一个应用程序,用户可以首先将所有联系人与桌面应用程序同步。这是通过web服务调用完成的,该调用从服务器获取一组100个联系人,下载并解析信息,将联系人插入Android联系人数据库,确认收到这些联系人,然后对下一组100个联系人重复前面的步骤,直到同步完成。当用户拥有订单上的联系人或1000-2000个联系人时,此过程非常有效,但此应用程序的典型用户可以轻松拥有5000-6000个联系人(超级用户拥有10000个以上的联系人),在这种情况下,所需时间远比我希望的长。例如,大约5300个联系人的样本集可能需要13.5分钟才能完成。不错,但我希望它至少和iOS一样高效,如果可能的话,iOS可以为相同的数据集运行大约8分钟

我已经记录了每一步所需的时间,毫不奇怪,瓶颈似乎是将数据插入安卓合约数据库。在浏览网页后,我发现插入数千个联系人几乎没有什么帮助,但我发现的内容似乎分为以下三类:

1) ContentProviderOperation——谷歌推荐的方式,它给了我5300个联系人13.5分钟的基线时间

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

3) 使用DatabaseUtils.InsertHelper和事务创建优化的批量插入——不幸的是,这似乎是面向那些创建自己的内容提供商的人的,因为您需要访问底层数据库作为实例变量,而我还没有看到如何使用本机contacts数据库实现这一点


有没有人有过插入5000多个联系人的经验,或者有任何其他可能的想法可以帮助我缩短时间?还是应该将ContentProviderOperation视为将要得到的优化?

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

你对3的分析是正确的


根设备上有一些选项可供内容提供商使用,但我怀疑这正是您想要的。

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

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.
public void insertContact(联系人列表:列表){
val queueSize=300//400
val contactQueue=contactList.size/queueSize
如果(contactQueue>0){
var startIndex=0
var endIndex=0
变量模板列表:列表?=null
totalQueue=contactQueue+1+smsQueue
用于(0..contactQueue中的i){
startIndex=i*queueSize
endIndex=startIndex+queueSize
endIndex=if(endIndex=插入的最大操作数){
mContext.getContentResolver().applyBatch(contacts contract.AUTHORITY,ops);
ops.clear();
}
}
如果(ops.size()>0)
mContext.getContentResolver().applyBatch(contacts contract.AUTHORITY,ops);
}
专用操作(ArrayList操作,
Request.ContactBean(联系人){
int backReference=ops.size();
添加(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT\u URI)
.withValue(contacts contract.raw contacts.ACCOUNT\u NAME,null)
.带值(contacts contract.RawC