web-dev-qa-db-fra.com

Tentative de rouvrir un objet déjà fermé sqlitedatabase

J'ai un databaseHandler. Je dois compter les lignes dans la table. L'application se bloque avec cette erreur: Android attempt to reopen an already-closed object sqlitedatabase.
J'utilise simplement ce code dans l'activité:

db.getContactsCount();

Mais l'application se bloque. De plus, je veux réinitialiser les tables (supprimer des lignes de table). J'ai ajouté la méthode ci-dessous: 

public void deleteTable() {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete("contacts", null, null);
    }

Cela fonctionne bien mais je ne peux pas utiliser celui-ci:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // Drop older table if existed
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_CONTACTS);

    // Create tables again
    onCreate(db);
}

C'est le databasehandler:

public class DatabaseHandler extends SQLiteOpenHelper {

// All Static variables
// Database Version
private static final int DATABASE_VERSION = 1;

// Database Name
private static final String DATABASE_NAME = "contactsManager";

// Contacts table name
private static final String TABLE_CONTACTS = "contacts";

// Contacts Table Columns names
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
private static final String KEY_PH_NO = "phone_number";

public DatabaseHandler(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
    String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_CONTACTS + "("
            + KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
            + KEY_PH_NO + " TEXT" + ")";
    db.execSQL(CREATE_CONTACTS_TABLE);
}

// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // Drop older table if existed
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_CONTACTS);

    // Create tables again
    onCreate(db);
}

/**
 * All CRUD(Create, Read, Update, Delete) Operations
 */

// Adding new contact
void addContact(Contact contact) {
    SQLiteDatabase db = this.getWritableDatabase();

    ContentValues values = new ContentValues();
    values.put(KEY_NAME, contact.getName()); // Contact Name
    values.put(KEY_PH_NO, contact.getPhoneNumber()); // Contact Phone

    // Inserting Row
    db.insert(TABLE_CONTACTS, null, values);
    db.close(); // Closing database connection
}

// Getting single contact
Contact getContact(int id) {
    SQLiteDatabase db = this.getReadableDatabase();

    Cursor cursor = db.query(TABLE_CONTACTS, new String[] { KEY_ID,
            KEY_NAME, KEY_PH_NO }, KEY_ID + "=?",
            new String[] { String.valueOf(id) }, null, null, null, null);
    if (cursor != null)
        cursor.moveToFirst();

    Contact contact = new Contact(Integer.parseInt(cursor.getString(0)),
            cursor.getString(1), cursor.getString(2));
    // return contact
    return contact;
}

// Getting All Contacts
public List<Contact> getAllContacts() {
    List<Contact> contactList = new ArrayList<Contact>();
    // Select All Query
    String selectQuery = "SELECT  * FROM " + TABLE_CONTACTS;

    SQLiteDatabase db = this.getWritableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);

    // looping through all rows and adding to list
    if (cursor.moveToFirst()) {
        do {
            Contact contact = new Contact();
            contact.setID(Integer.parseInt(cursor.getString(0)));
            contact.setName(cursor.getString(1));
            contact.setPhoneNumber(cursor.getString(2));
            // Adding contact to list
            contactList.add(contact);
        } while (cursor.moveToNext());
    }

    // return contact list
    return contactList;
}

// Updating single contact
public int updateContact(Contact contact) {
    SQLiteDatabase db = this.getWritableDatabase();

    ContentValues values = new ContentValues();
    values.put(KEY_NAME, contact.getName());
    values.put(KEY_PH_NO, contact.getPhoneNumber());

    // updating row
    return db.update(TABLE_CONTACTS, values, KEY_ID + " = ?",
            new String[] { String.valueOf(contact.getID()) });
}

// Deleting single contact
public void deleteContact(Contact contact) {
    SQLiteDatabase db = this.getWritableDatabase();
    db.delete(TABLE_CONTACTS, KEY_ID + " = ?",
            new String[] { String.valueOf(contact.getID()) });
    db.close();
}


// Getting contacts Count
public int getContactsCount() {
    String countQuery = "SELECT  * FROM " + TABLE_CONTACTS;
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery(countQuery, null);
    cursor.close();

    // return count
    return cursor.getCount();
}

public void Upgrade (SQLiteDatabase db, int oldVersion, int newVersion) {
    String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_CONTACTS + "("
            + KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
            + KEY_PH_NO + " TEXT" + ")";
    db.execSQL(CREATE_CONTACTS_TABLE);
}

// Deleting single contact
    public void deleteTable() {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete("contacts", null, null);
    }
}
10
Namikaze Minato

Cela se produit à cause de:

db.close();

dans les méthodes:

void addContact(Contact contact)

public void deleteContact(Contact contact)

Vous ne devez pas fermer la connexion à la base de données sous-jacente à moins que vous vraiment n'ayez plus l'intention de l'utiliser. Utilisez SQLiteOpenHelper:close, lorsque vous avez terminé votre travail.

De plus, les appels à getReadableDatabase() et getWriteableDatabase() renvoient le même objet de base de données 99% du temps, et ils ne pasréinitialiser la connexion à la base de données fermée manuellement par vous. 

Ne vous laissez pas berner par ces noms de méthodes.

18
Drew

Je voudrais vous suggérer de ne pas fermer un objet de base de données avant d’achever vos travaux de base de données.

SQLiteDatabase db;
db = this.getWritableDatabase();

or

db = this.getReadableDatabase();

Au-dessus des deux méthodes, donnez-nous un objet de base de données à l'aide de la classe helper. Cet objet permet d'effectuer différentes actions sur la base de données. Mais dans votre scénario, je pense que vous avez donc fermé un objet de base de données avant de terminer l'opération. Donc fermé après avoir terminé toutes les opérations en utilisant 

db.close();
7
Kailas Bhakade

cela se produit essentiellement à cause de cursor.close (); puisque vous fermez l'objet curseur avant de renvoyer son compte.

3
Ruchit Jain

J'aurais dû définir int count = cursor.getCount(); avant de fermer la base de données. Il semble que return cursor.getCount(); après la fermeture de la base de données soit un effort inutile.
Enfin, il était nécessaire de supprimer db.close(); à la fin des méthodes delete et remove.
Ajouter ce code à la place dans le gestionnaire a beaucoup aidé:

public void closeDB() {
    SQLiteDatabase db = this.getReadableDatabase();
    if (db != null && db.isOpen())
        db.close();
}

La manipulation de la fonction close à l'intérieur de l'activité à la fin de l'utilisation de la base de données était meilleure. Merci à @Drew.
Je ne comprends toujours pas l’utilisation de onUpgrade dans le gestionnaire ???

2
Namikaze Minato

OnUpgrade est le moment où vous apportez des modifications à votre base de données (c'est-à-dire en ajoutant des tables). Il existe donc une nouvelle version de votre base de données. Votre:

private static final int DATABASE_VERSION = 1;

est maintenant 

private static final int DATABASE_VERSION = 2;

Comme la version de la base de données est désormais la version la plus récente, la méthode OnUpgrade () est appelée et met à jour la base de données.