【问题标题】:Ormlite query takes time in AndroidOrmlite 查询在 Android 中需要时间
【发布时间】:2015-08-23 22:19:24
【问题描述】:

我正在使用 ormlite 的 Android 应用程序中工作。我正在获取我的电话簿联系人并将它们保存在我的本地数据库中,但问题是它花费了太多时间,比如几乎 1500 个联系人需要将近 70 秒。

我在 ormlite 中搜索了 Bulk insert,但我无法弄清楚如何在我的以下代码中实现它。

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();
            }
        }
    }

【问题讨论】:

  • 一种可能的优化是根本不查询Contacts.CONTENT_URI。相反,您可以查询 Phone.CONTENT_URI 并将联系人列包含在投影中。您只需要这个光标,无需进行进一步查询,但您必须更改代码以查找每个新联系人的开始位置。

标签: java android bulkinsert ormlite


【解决方案1】:

问题在于它花费了太多时间,例如几乎 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

因此,您将进行一次查询以查看需要创建哪些联系人,然后从批处理事务中执行所有插入操作。

否则,您将在 Android 设备上执行约 3000 个同步数据库事务,而 40/秒是很典型的。

【讨论】:

    【解决方案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 有一个createOrUpdate 方法,它与您之前的@​​987654328@ if 语句相同。

    【讨论】:

      猜你喜欢
      • 2015-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-02
      相关资源
      最近更新 更多