Android SQLite и огромные наборы данных - PullRequest
19 голосов
/ 11 сентября 2009

Мы создаем приложение для клиента с сотнями мегабайт HTML в базах данных SQLite. Мы реализовали способ запрашивать эти данные и прокручивать их все достаточно быстро. Проблема заключается в том, что некоторые базы данных имеют очень большие запросы (более 20 000 строк), и мы видим ошибки при увеличении количества запросов по мере прокрутки пользователем. Поэтому я думаю, что вопрос в том, какие у нас есть возможности запрашивать и отображать десятки тысяч строк данных в Android?

Вот трассировка стека, которую мы видим:

09-10 19:19:12.575: WARN/IInputConnectionWrapper(640): showStatusIcon on inactive InputConnection
09-10 19:19:18.226: DEBUG/dalvikvm(640): GC freed 446 objects / 16784 bytes in 330ms
09-10 19:19:32.886: ERROR/CursorWindow(19416): need to grow: mSize = 1048576, size = 36, freeSpace() = 30, numRows = 17717
09-10 19:19:32.896: ERROR/CursorWindow(19416): not growing since there are already 17717 row(s), max size 1048576
09-10 19:19:32.916: ERROR/CursorWindow(19416): The row failed, so back out the new row accounting from allocRowSlot 17716
09-10 19:19:33.005: ERROR/Cursor(19416): Failed allocating fieldDir at startPos 0 row 17716
09-10 19:19:35.596: DEBUG/Cursor(19416): finish_program_and_get_row_count row 24315
09-10 19:19:41.545: DEBUG/dalvikvm(698): GC freed 2288 objects / 126080 bytes in 260ms
09-10 19:19:43.705: WARN/KeyCharacterMap(19416): No keyboard for id 0
09-10 19:19:43.717: WARN/KeyCharacterMap(19416): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
09-10 19:20:04.705: ERROR/CursorWindow(19416): need to grow: mSize = 1048576, size = 17, freeSpace() = 3, numRows = 17094
09-10 19:20:04.716: ERROR/CursorWindow(19416): not growing since there are already 17094 row(s), max size 1048576
09-10 19:20:04.726: ERROR/Cursor(19416): Failed allocating 17 bytes for text/blob at 17093,2
09-10 19:20:05.656: DEBUG/Cursor(19416): finish_program_and_get_row_count row 5257
09-10 19:24:54.685: DEBUG/dalvikvm(637): GC freed 9297 objects / 524176 bytes in 247ms
09-10 19:32:07.656: DEBUG/dalvikvm(19416): GC freed 9035 objects / 495840 bytes in 199ms

Вот наш код CursorAdapter:

    private class MyAdapter extends ResourceCursorAdapter {

    public MyAdapter(Context context, Cursor cursor) {
        super(context, R.layout.my_row, cursor);        
    }

    public void bindView(View view, Context context, Cursor cursor) {                
        RowData data = new RowData();
        data.setName(cursor.getInt(cursor.getColumnIndex("name")));

        TextView tvItemText = (TextView)view.findViewById(R.id.tvItemText);
        tvItemText.setText(data.getName());

        view.setTag(data);
    }

    @Override
    public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
        /* Display the progress indicator */
        updateHandler.post(onFilterStart);

        /* Run the actual query */               
        if (constraint == null) {
            return myDbObject.getData(null);                     
        }

        return myDbObject.getData(constraint.toString());                
    }            
}

Ответы [ 3 ]

26 голосов
/ 11 сентября 2009

какие у нас есть варианты запросов и показывая десятки тысяч строки данных в Android?

Вы имеете в виду, помимо того, что говорите, что чтение 20 000+ строк на 3,5-дюймовом ЖК-дисплее - это безумие для бат-гуано?

Похоже, что CursorWindow, который используется где-то под обложками, имеет проблемы с управлением> 17 000 строк. Это может быть одна из двух вещей:

  1. Вам не хватает места в куче. С некомпактной кучей 16 МБ и тем фактом, что Cursor содержит весь набор результатов в куче, об этом не может быть и речи.
  2. CursorWindow поддерживает только 1 МБ данных, что более точно указывает сообщение об ошибке.

Если есть логический способ разделить ваши запросы на отдельные порции, вы можете выполнять инкрементные запросы и использовать CursorJoiner, чтобы соединить их вместе, и посмотреть, поможет ли это.

Но, если серьезно, 20 000+ строк на 3,5-дюймовом экране на устройстве, которое больше всего напоминает 12-летний ПК в лошадиных силах, действительно требует много.

6 голосов
/ 27 марта 2012

Если вам это действительно нужно, вы также можете разделить свои данные и читать их как:

   int limit = 0;
   while (limit + 100 < numberOfRows) {
       //Compose the statement
       String statement = "SELECT * FROM Table ORDER someField LIMIT '"+ limit+"', 100";
       //Execute the query
       Cursor cursor = myDataBase.rawQuery(statement, null);
       while (cursor.moveToNext()) {
           Product product = new Product();
           product.setAllValuesFromCursor(cursor);
           productsArrayList.add(product);
      }
      cursor.close();
      limit += 100;
 }

 //Compose the statement
 String statement = "SELECT * FROM Table ORDER someField LIMIT '"+  (numberOfRows - limit)+"', 100";
 //Execute the query
 Cursor cursor = myDataBase.rawQuery(statement, null);

 while (cursor.moveToNext()) {
     Product product = new Product();
     product.setAllValuesFromCursor(cursor);
     productsArrayList.add(product);
 }
 cursor.close();

Если у вас есть индексированная таблица, он работает менее чем за 2 с для строк из 5 000 строк.

Спасибо, Arkde

0 голосов
/ 18 июля 2013

По моему опыту, ограничение количества запросов приводит к тому, что получение результатов занимает гораздо больше времени, поскольку запуск новых курсоров обходится дорого для низких пределов. Я только что попытался сделать строки по 62 КБ с лимитом 1 КБ и даже 10 КБ, и это очень медленно и непригодно для использования, поскольку мне нужно запустить более 6 курсоров. Я просто остановлюсь на том, что не поддерживаю 2.3.3 .... Это последняя сборка, в которой я получаю CursorWindow ERROR вместо WARN.

Вот что я сделал, хотя. Это, наверное, лучший алгоритм, я думаю. Не нужно делать запросы дважды и т. Д. Однако, это может быть довольно медленно с большими запросами и небольшими ограничениями, поэтому вы должны проверить, что работает лучше всего. В моем случае это не достаточно быстро для моих целей, так как он плохо обрабатывает 62 тыс. Строк.

int cursorCount = 0;
int limit = 1000; //whatever you want
while (true)
{
    Cursor cursor = builder.query(mDatabaseHelper.getReadableDatabase(), columns, selection, selectionArgs, null, null, null, Integer.toString(limit));
    if (cursor == null) {
        return null;
    } else if (!cursor.moveToFirst()) { //if it is empty, return null
        return null;
    }
    cursorCount = cursor.getCount();
    if (cursorCount % limit != 0)
    {
        return cursor;
    }
    limit+=1000; //same amount as the one above
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...