java - sqliteconstraintexception - sqlite android studio 2018
Android SQLite y grandes conjuntos de datos (3)
¿Qué opciones tenemos para consultar y mostrar decenas de miles de filas de datos en Android?
Quieres decir, además de decirte que leer más de 20,000 filas en una pantalla LCD de 3.5 "está loco como un murciélago-guano ?-
Parece que CursorWindow
, que se usa en algún lugar debajo de las portadas, tiene problemas para administrar> 17,000 filas. Eso podría ser una de dos cosas:
- Usted está fuera del espacio de pila Con un montón no compacto de 16MB, y el hecho de que un
Cursor
mantenga todo el conjunto de resultados en el montón, no está fuera de discusión. -
CursorWindow
solo admite 1 MB de datos, que es lo que el mensaje de error sugiere más directamente.
Si hay una forma lógica de dividir sus consultas en CursorJoiner
discretas, puede hacer consultas incrementales y usar CursorJoiner
para unirlas, y ver si eso ayuda.
Pero, con toda seriedad, más de 20,000 filas en una pantalla de 3.5 ", en un dispositivo que se parece mucho a una PC de 12 años con potencia, realmente está pidiendo mucho.
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 desplazarnos a través de todos ellos 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 aumentamos las consultas a medida que el usuario se desplaza. Entonces, supongo que la pregunta es, ¿qué opciones tenemos para consultar y mostrar 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());
}
}
En mi experiencia, limitar las consultas hace que la obtención de resultados tarde mucho más tiempo, ya que comenzar con nuevos cursores es costoso para los límites bajos. Intenté hacer 62k filas con un límite de 1k e incluso 10k justo ahora y es muy lento e inutilizable, ya que tengo que iniciar más de 6 cursores. Me limitaré a no admitir 2.3.3 ... Es la última versión que obtengo CursorWindow ERROR en lugar de WARN.
Esto es lo que hice sin embargo. Este es probablemente el mejor algoritmo, creo. No tiene que hacer consultas dos veces, etc. Sin embargo, puede ser bastante lento con consultas grandes y límites pequeños, por lo que debe probar lo que mejor funciona mucho. En mi caso, no es lo suficientemente rápido para mis propósitos, ya que no maneja bien las filas de 62k.
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
}
Si realmente necesitas eso, también puedes dividir tus datos y leer fragmentos 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á funcionando en 2 s para 5k filas si tiene una tabla indexada.
Gracias arde