Сбой запроса Android SQLite, когда он занимает слишком много времени? - PullRequest
0 голосов
/ 13 августа 2011

У меня есть запрос SQLite в моем приложении для Android, который кажется сбой, когда он выполняется слишком долго. Вылетает с NullPointerException и сообщает мне номер строки ...

Когда я ставлю точки останова вокруг этой строки и вижу, что она всегда заполняется переменной, приложение не падает и делает то, что должно.

Таким образом, помимо наличия фантомного нулевого указателя, проблема состоит в том, что точки останова на самом деле замедляют работу, давая время для выполнения запроса. Без точек останова всегда происходит сбой.

Другие здесь, похоже, имеют аналогичную проблему, и я читал некоторые вещи о том, что SQLite тратит много времени на выполнение задач, но в этой таблице должно быть всего несколько записей (ту, которую я тестирую) должно иметь только три записи, 4 столбца)

Предложения о том, как сделать так, чтобы он не падал? Возможно, поместить ожидание потока в метод, который делает запрос?

 public void fetchItemsToRemove() throws SQLException{
    Cursor mCursor =
            mapDb.query(myMain_TABLE, new String[] {myOtherId, myCustomID, myDATE}, null, null, null, null, null);

    if(mCursor.moveToFirst())
    {
            do
            {
                /*taking "dates" that were stored as plain text strings, and converting them to 
                *Date objects in a particular format for comparison*/

                String DateCompareOld = mCursor.getString(mCursor.getColumnIndex(myDATE));
                String DateCompareCurrent = "";
                Date newDate = new Date();
                DateCompareCurrent = newDate.toString();

                try {
                    DateCompareOld = (String)DateCompareOld.subSequence(0, 10);
                    DateCompareCurrent = (String)DateCompareCurrent.subSequence(0, 10);
                    SimpleDateFormat dateType =  new SimpleDateFormat("EEE MMM dd");
                    Date convertDate = dateType.parse(DateCompareOld);

                    newDate = dateType.parse(DateCompareCurrent);

                    if(convertDate.compareTo(newDate) < 0)
                    {
                        //remove unlim id
                        mapDb.delete(myMain_TABLE, myDATE + "=" + mCursor.getString(mCursor.getColumnIndex(myDATE)), null);

                    }

                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }while(mCursor.moveToNext());
            mCursor.close();
    }
    else
    {
        mCursor.close();    
    }


}

Теперь "строка 342", где происходит сбой с NullPointerException, равна DateCompareOld = (String)DateCompareOld.subSequence(0, 10);, где она получает подпоследовательность строки. Если он попадает сюда и имеет значение null, это означает, что строка никогда не была заполнена в String DateCompareOld = mCursor.getString(mCursor.getColumnIndex(myDATE));

как будто запрос только что был пропущен, потому что это заняло слишком много времени. Обратите внимание, что это время цикла, и я провел тесты, чтобы убедиться, что mCursor никогда не выходит за пределы.

1 Ответ

2 голосов
/ 13 августа 2011

Вы удаляете вещи из таблицы БД, одновременно просматривая результаты запроса из этой таблицы. Звучит немного опасно.

Попробуйте создать внутри цикла список подлежащих удалению вещей, а затем удалите их за один раз после завершения цикла.

Кроме того, оберните все это в транзакцию БД. Когда вы модифицируете БД в цикле, это может сильно повлиять на производительность.

РЕДАКТИРОВАТЬ : краткое объяснение транзакций:

Транзакция позволяет объединить несколько запросов / модификаций БД в одну атомарную операцию, которая либо завершается успешно, либо завершается неудачно. Это в первую очередь механизм безопасности, поэтому ваша БД не застревает в несогласованном состоянии, если на полпути что-то идет не так, но это также означает, что любые изменения фиксируются в хранилище файлов БД в одном кадре, а не по одному, что намного быстрее.

Вы запускаете транзакцию в начале своей функции:

public void fetchItemsToRemove() throws SQLException{
    db.beginTransaction();
    Cursor mCursor = ....

Вы устанавливаете его как успешный, если вся функция завершается без ошибок. Это, вероятно, означает, что вы хотите удалить внутренний try/catch и иметь внешний try/catch, охватывающий цикл. Затем в конце try{ } вы можете предположить, что ничего не случилось, поэтому вы звоните:

db.setTransactionSuccessful(); 

Затем в предложении finally убедитесь, что вы всегда закрываете транзакцию независимо от того, успешна она или нет:

db.endTransaction();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...