SQLite
 sql >> Database >  >> RDS >> SQLite

Problema di memoria SQLite con approccio singleton

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.