Ormlite查询在Android中需要时间

时间:2015-08-23 22:19:25

标签: java android bulkinsert ormlite

我在使用ormlite的Android应用程序中工作。我正在接收我的电话簿联系人并将其保存在我的本地数据库中,但问题是它需要花费太多时间,例如近1500次接触,这需要将近70秒。

我在ormlite中搜索了批量插入内容,但我无法在以下代码中弄清楚如何实现它。

public static void loadLocalPhoneBookSample(Context ctx) {

        try{

        ContentResolver contentRes = ctx.getContentResolver();
        Cursor cur = null;

        String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER;
        cur = contentRes.query(ContactsContract.Contacts.CONTENT_URI, PROJECTIONS, selection, null, Phone.DISPLAY_NAME + " ASC");
        context = ctx;

        if (cur.getCount() > 0) {

            // create DB object
            MUrgencyDBHelper db = new MUrgencyDBHelper(ctx);
            RuntimeExceptionDao<ContactLocal, ?> contactDAO = db.getContactLocalIntDataDao();

            UpdateBuilder<ContactLocal, ?> updateDAO = contactDAO.updateBuilder();
            try {

                updateDAO.updateColumnValue("isUseless", true);
                updateDAO.update();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
//              db.writeUnlock();
            }


            while (cur.moveToNext()) {
                String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));

                /** read names **/
                String displayName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                /** Phone Numbers **/

                Cursor pCur = contentRes.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID
                + " = ?", new String[] { id }, null);

                while (pCur.moveToNext()) {

                    String number = pCur
                            .getString(pCur
                                    .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

String formatedNo = number.replaceAll("\\s+", "").replace("+", "00").replace("-", "").trim();

                        try {

                            QueryBuilder<ContactLocal, ?> query = contactDAO.queryBuilder();
                            query.where().eq("mFormatedNumber", number);

                            ContactLocal contact = query.queryForFirst();
                            boolean addContact = false, alreadyUpdated = true;

                            if (contact == null) {
                                addContact = true;
                                contact = new ContactLocal();
                                contact.setFirstName(displayName.trim());
                                contact.setLastName(displayName.trim());
                                contact.setContactNumber(formatedNo);
                            }

                            // check if this contact was already updated before
                            if (contact.getContactNumber() == null || contact.getContactNumber().length() == 0) {
                                contact.setContFirstLastNo(number, displayName, displayName, number);
                                alreadyUpdated = false;
                            }

                            contact.setUseless(false);

                            // if not updated already, Create/Update
                            if (addContact) {
                                contactDAO.create(contact);
                            } else
                                contactDAO.update(contact);
                        } 
                }

                pCur.close();
            }
        }
    }

2 个答案:

答案 0 :(得分:2)

这是我的修订版本(可能需要一些语法更改)

public static void loadLocalPhoneBookSample(Context ctx) {
try {
    ContentResolver contentRes = ctx.getContentResolver();
    String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER;
    Cursor cur = contentRes.query(ContactsContract.Contacts.CONTENT_URI, PROJECTIONS, selection, null, Phone.DISPLAY_NAME + " ASC");
    context = ctx;

    if (cur.getCount() > 0) {

        // create DB object
        MUrgencyDBHelper db = new MUrgencyDBHelper(ctx);
        RuntimeExceptionDao<ContactLocal, ?> contactDAO = db.getContactLocalIntDataDao();

        UpdateBuilder<ContactLocal, ?> updateDAO = contactDAO.updateBuilder();
        try {
            updateDAO.updateColumnValue("isUseless", true);
            updateDAO.update();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //              db.writeUnlock();
        }

        ArrayList<ContactLocal> contacts = new ArrayList<>();
        while (cur.moveToNext()) {
            String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));

            /** read names **/
            String displayName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

            /** Phone Numbers **/               
            Cursor pCur = contentRes.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null);
            while (pCur.moveToNext()) {

                String number = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                String formatedNo = number.replaceAll("\\s+", "").replace("+", "00").replace("-", "").trim();

                try {
                    QueryBuilder<ContactLocal, ?> query = contactDAO.queryBuilder();
                    query.where().eq("mFormatedNumber", number);

                    ContactLocal contact = query.queryForFirst();

                    if (contact == null) {
                        contact = new ContactLocal();
                        contact.setFirstName(displayName.trim());
                        contact.setLastName(displayName.trim());
                        contact.setContactNumber(formatedNo);
                    }

                    contact.setUseless(false);
                    contacts.add(contact);
                } 
            }
            pCur.close();

        }
        contactDao.callBatchTasks(new Callable<Void>() {
            public Void call() throws Exception {
                for (ContactLocal contact : contacts) {
                    contactDAO.createOrUpdate(contact);
                }
            }
        });
    }
}

主要优化是使用callBatchTasks。从ormlite文档:

  

默认情况下,数据库在每次SQL操作后都会更改。此方法禁用此“自动提交”行为,因此可以更快地进行一些更改,然后一次全部提交。

通过创建ArrayList并跟踪更改,您可以一次性使用callBatchTasks创建/更新。

此外,我注意到alreadyUpdated从未被访问过,因此可以安全删除。

同样Dao的{​​{1}}方法与之前的createOrUpdate if语句相同。

答案 1 :(得分:2)

  

问题在于它需要花费太多时间,例如近1500次接触需要花费近70秒

@CarloB在dao. callBatchTasks(...)方法中进行质量创建方面有正确的答案。这是关于该主题的文档:

  

http://ormlite.com/docs/batch

为了让事情变得更快,您还可以浏览并记录另一个mFormatedNumber中的所有List,然后使用IN查询查询它们。使用原始查询来获取数据库中已有的mFormatedNumber

results = dao.queryRaw(
    "SELECT mFormatedNumber from Contact WHERE mFormatedNumber IN ?",
    mFormatedNumberList);

对于使用ORMLite的原始查询,请参阅:

  

http://ormlite.com/docs/raw-queries

那么您可以进行一次查询以查看需要创建哪些联系人,然后在批处理事务中执行所有插入。

否则,您正在进行~3000个同步数据库事务,并且在Android设备上40 /秒很不典型。