Se ricevi un messaggio che indica troppi file aperti, una causa potrebbe essere la presenza di troppi cursori ancora aperti.
Tuttavia, il messaggio restituito potrebbe non essere sempre lo stesso ed è probabilmente specifico dell'attività/chiamata chiamata.
In questo caso il messaggio era (unable to open database file (code 2062))
, ancora in un altro caso (da SELECT il messaggio era unable to open database file (code 14)
). SQLite non è in grado di aprire il file di database (codice 14) su query "SELECT" frequenti.
Il collegamento sopra punta anche a un post che ho creato e che mostra chiaramente che la creazione di un cursore comporta l'apertura di uno o più file.
L'esempio scorreva su circa 500 righe e per ogni riga stava creando/ricreando 3 cursori per ogni riga (quindi potenzialmente più di 1500 cursori anche se utilizzavano solo 4 oggetti cursore).
Inizialmente chiudeva solo i 3 cursori alla fine (ultima riga del genitore di tutti) risultando in unable to open database File (code 14)
. La chiusura dei 3 cursori per ogni iterazione ha risolto il problema.
Il codice non riuscito era :-
SQLiteDatabase db = getWritableDatabase();
Cursor shoplistcursor = getAllRowsFromTable(SHOPLIST_TABLE_NAME);
Cursor productcsr;
Cursor aislecsr;
Cursor prdusecsr;
while(shoplistcursor.moveToNext()) {
productcsr = getProductFromProductId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
aislecsr = getAisleFromAisleId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)));
prdusecsr = getProductUsage(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)),
shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
if (productcsr.getCount() < 1 | aislecsr.getCount() < 1 | prdusecsr.getCount() < 1) {
deleteShopListEntry(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_ID)));
}
if(shoplistcursor.isLast()) {
prdusecsr.close();
aislecsr.close();
productcsr.close();
}
}
shoplistcursor.close();
db.close();
}
Mentre il codice fisso era :-
SQLiteDatabase db = getWritableDatabase();
Cursor shoplistcursor = getAllRowsFromTable(SHOPLIST_TABLE_NAME);
Cursor productcsr;
Cursor aislecsr;
Cursor prdusecsr;
while(shoplistcursor.moveToNext()) {
productcsr = getProductFromProductId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
aislecsr = getAisleFromAisleId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)));
prdusecsr = getProductUsage(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)),
shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
if (productcsr.getCount() < 1 | aislecsr.getCount() < 1 | prdusecsr.getCount() < 1) {
productcsr.close();
aislecsr.close();
prdusecsr.close();
deleteShopListEntry(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_ID)));
} else {
productcsr.close();
aislecsr.close();
prdusecsr.close();
}
}
shoplistcursor.close();
db.close();
}
Tendo ora a seguire la seguente regola/pratica :-
-
Se si ottiene solo il risultato, ad es. ottenendo il numero di righe, chiudi il Cursore nel metodo.
-
Se si utilizza il cursore per una visualizzazione ad es. a ListView, quindi chiudi il cursore nel
onDestroy
dell'attività metodo. -
Se si utilizza il cursore per ciò che chiamerò un'elaborazione più complessa, ad es. eliminare le righe con riferimenti sottostanti, quindi chiudere i cursori non appena hanno terminato, all'interno dei cicli di elaborazione.