Android SQLite y enormes conjuntos de datos

Estamos creando una aplicación para un cliente que tiene cientos de megabytes de HTML en bases de datos SQLite. Hemos implementado una forma de consultar estos datos y desplazarse por todo ello de una manera razonablemente rápida. El problema es que algunas de las bases de datos tienen consultas muy grandes (más de 20.000 filas) y estamos viendo errores cuando estamos creciendo las consultas a medida que el usuario se desplaza. Así que supongo que la pregunta es, ¿qué opciones tenemos en la consulta y la visualización de decenas de miles de filas de datos en Android?

Aquí está el stacktrace que estamos viendo:

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 

Aquí está nuestro código 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()); } } 

Qué opciones tenemos en la consulta y la visualización de decenas de miles de filas de datos en Android?

¿Quieres decir además de decirle que la lectura de 20.000 + filas en un LCD de 3,5 "es el palo-guano loco ?;-)

Parece que CursorWindow , que se utiliza en algún lugar bajo las cubiertas, tiene problemas para gestionar> 17.000 filas. Ésa podría ser una de dos cosas:

  1. Usted está fuera del montón de espacio. Con un montón de 16 MB sin compactación, y el hecho de que un Cursor mantiene todo el conjunto de resultados en el montón, eso no está fuera de la cuestión.
  2. CursorWindow sólo admite 1 MB de datos, que es lo que el mensaje de error sugiere más directamente.

Si hay una manera lógica de dividir sus consultas en trozos discretos, puede realizar consultas incrementales y utilizar CursorJoiner para CursorJoiner juntas, y ver si eso ayuda.

Pero, con toda seriedad, 20.000 filas más en una pantalla de 3.5 ", en un dispositivo que se asemeja más a una PC de 12 años en caballos de fuerza, realmente está pidiendo mucho.

Si realmente necesita que también puede dividir sus datos y leer trozos como este:

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

Está trabajando debajo de 2 s para las filas 5k si usted tiene tabla indizada.

Gracias, Arkde

En mi experiencia, limitar las consultas hace que tome mucho más tiempo obtener resultados porque iniciar nuevos cursores es caro para límites bajos. Intenté hacer 62k filas con 1k e incluso 10k límite ahora mismo y es muy lento e inutilizable ya que tengo que empezar más de 6 cursores. Me quedo con no apoyar 2.3.3 …. Es la última versión que tengo CursorWindow ERROR en lugar de WARN.

Aquí es lo que hice sin embargo. Este es probablemente el mejor algoritmo que creo. No tiene que hacer las consultas dos veces, etc Sin embargo, puede ser bastante lento con grandes consultas y pequeños límites por lo que tiene que probar lo que funciona mejor mucho. En mi caso, no es lo suficientemente rápido para mis propósitos ya que no maneja 62k filas bien.

 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 } 
  • Android Bluetooth java.io.IOException: Conexión rechazada?
  • GoogleMap dentro de un fragmento en un ViewPager, guarda todos los eventos de toque en GoogleMap
  • Cómo analizar los resultados de JSON de Unirest llamada
  • Detectar videollamada entrante en android
  • Cómo agregar un escucha a un botón de conmutación?
  • Firmar un apk como sistema usando las claves encontradas en source / build / target / product / security /
  • Android Wear: ¿Hay alguna razón para utilizar un objeto Time en lugar de un objeto Calendar?
  • Android y fuzzy matching, n-gram y distancia de Levenshtein
  • No se puede encontrar la clase de símbolo Intent
  • Búsqueda de Android con Fragmentos
  • ¿Hay algún diseñador de formularios disponible para Google Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.