2012-09-25 19 views
16

Tengo un problema de memoria que no puedo resolver. Tengo una clase que hace todo el trabajo de recuperación de mi base de datos. El error que tengo es la siguiente: Error de asignación deSin memoria al asignar cursores

android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=733 (# cursors opened by this proc=733) 

la memoria se produce cuando hago esto:

mDatabaseInterface.getGraphForLevel(level); 

Sé que es una fuga, ya que llamo este método cada 2,5 segundos o menos, y el 5 o 6 primeras llamadas pasan fácilmente. Ahora aquí están los métodos de mi clase DatabaseInterface:

public Graph getGraphForLevel(Level level) { 

    //get the nodes 
    ArrayList<Node> nodes = new ArrayList<Node>(Arrays.asList(this.getNodesWithLevel(level))); 
    //get the edges 
    ArrayList<Edge> edges = new ArrayList<Edge>(Arrays.asList(this.getEdgesWithNodes(nodes))); 

    return new Graph(nodes, edges); 
} 

public Node[] getNodesWithLevel(Level level) { 

    List<Node> l = new ArrayList<Node>(); 

    Cursor cursor = mDatabase.query("nodes", null, 
      "level = " + wrapSql(String.valueOf(level.getId())), null, null, null, null); 

    while (cursor.moveToNext()) { 
     l.add(parseNodeFromCursor(cursor)); 
    } 

    cursor.close(); 

    return l.toArray(new Node[l.size()]);  
} 

private Node parseNodeFromCursor(Cursor cursor) { 

    Level l = getLevelWithId(cursor.getInt(2)); 

    return new Node(cursor.getInt(0), cursor.getString(1), l, 
      cursor.getInt(4), cursor.getInt(5)); 
} 

tengo una gran cantidad de métodos que se llaman entre sí, pero sé que no es un problema debido a la recursividad esta clase trabaja en otra aplicación. Mi pregunta principal es ¿por qué no cursor.close() libera el cursor? Si hago algo como:

cursor = mDatabase.query(...); 
cursor.moveToNext(); 
Node node = new Node(cursor.getInt()); 
cursor.close(); 

¿Se retiene el cursor en ese caso?

Gracias de antemano.

+0

Solo para hacerte una idea, ¿qué tan grandes son las tablas para nodos y bordes? – Matthieu

+0

Son muy pequeños por ahora, 20 filas y 10 columnas a lo sumo – chopchop

Respuesta

27

La llamada a cursor.close() debe estar en un bloque finally en caso de que se produzca una excepción mientras se itera sobre ella.

Cursor cursor = mDatabase.query("nodes", null, 
     "level = " + wrapSql(String.valueOf(level.getId())), null, null, null, null); 
try { 
    while (cursor.moveToNext()) { 
     l.add(parseNodeFromCursor(cursor)); 
    } 
} finally { 
    cursor.close(); 
} 
+0

gracias rodeando finalmente resuelto – chopchop

9

Uno de los motivos por los que ocurre un error de falta de memoria es you are not closing your cursor.

Como puedo ver, está llamando al cursor.close(), pero ¿es el lugar correcto donde debe llamar a este método o comprobar si debe cerrarlo en otro lugar?

EDIT:

Si su actividad es managing your Cursor, puede considerar dejar de administrar y cerrar todo en el método , y en onResume todo abierto y fillData una vez más.

+0

por favor vea mi edición – Shrikant

+0

mmm gracias, revisé a fondo mi código y pensé que lo había arreglado. Pero volvió después de 10 minutos de funcionamiento (¡mucho mejor que 10 segundos!). Pero ahora, en lugar de 733 o más cursores, se bloquea con solo 4 cursores abiertos. android.database.CursorWindowAllocationException: la asignación de la ventana del cursor de 2048 kb ha fallado. # Cursores abiertos = 4 (# cursores abiertos por este proceso = 4) – chopchop

+0

Bien. Entonces, si está utilizando un objeto global de cursor, primero intente borrar el contenido del cursor y luego vuelva a llenar los datos en él, de modo que el contenido del cursor no exceda el umbral. – Shrikant