Hello tout le monde,

J'ai appliqué les méthodes découvertes sur les tutos du site android pour commencer mon petit projet : en gros, une application qui va chercher des infos sur Internet, stocke une partie dans des bases pour le réutiliser, et les ressortir à l'écran.

Bon, je rame pas mal, mais dans l'ensemble, ça se passe bien

J'ai juste un problème qui me chagrine: dans le tuto notepad, ils décrivent très bien comment gérer une table dans une base SQLite. J'ai suivi le même principe pour mon appli, et ça marche. Le truc, c'est que moi, je vais avoir 4/5 tables en tout. Si je suis exactement leur principe, soit je gère mes 4/5 tables dans une seule classe, et je trouve que c'est brouillon, soit je réplique 4/5 fois la classe, mais vu qu'elle gère la table ET la base, je "dois" utiliser une base différente pour chaque table (ce que je ne trouve pas forcément adapté).

J'ai voulu faire un mix, mais ça ne marche pas à cause d'une erreur étrange que je vais vous présenter ci-dessous =) J'ai évidemment viré pas mal de trucs du code pour le rendre plus lisible, mais je pense qu'il y a l'essentiel pour comprendre.

Exemple avec une classe pour une table qui fait tout (donc une classe par table par base à priori) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Table1DbAdapter {
 
    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;
 
    private static class DatabaseHelper extends SQLiteOpenHelper {
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(DATABASE_CREATE);
        }
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL(TABLE_1_DROP);
            onCreate(db);
        }
    }
 
    public NotesDbAdapter(Context ctx) {
        this.mCtx = ctx;
    }
 
    public NotesDbAdapter open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }
 
    public void close() {
        mDbHelper.close();
    }
 
	public boolean isEmpty() {
		return (mDb.query(TABLE_NAME, new String[] {KEY_ROWID}, null, null, null, null, null).getCount() == 0);
	}
}
Exemple avec une classe qui gère les appels aux classes de chaque table:
la classe globale
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class GlobalDAdapter {
 
    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;
 
    private Table1DbAdapter mTable1DbHelper;
    private Table2DbAdapter mTable2DbHelper;
 
    private static class DatabaseHelper extends SQLiteOpenHelper {
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
        public void onCreate(SQLiteDatabase db) {
            Log.i(TAG, "Creating table 1.");
            db.execSQL(TABLE_2_CREATE);
            Log.i(TAG, "Creating table 2.");
            db.execSQL(TABLE_2_CREATE);
        }
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL(TABLE_1_DROP);
            db.execSQL(TABLE_2_DROP);
            onCreate(db);
        }
    }
 
    public GlobalDAdapter(Context ctx) {
    	this.mCtx = ctx;
	}
 
    public GlobalDAdapter open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
 
		mTable1DbHelper = new Table1DbAdapter(mDb);
		mTable2DbHelper = new Table2DbAdapter(mDb);
 
        return this;
    }
 
    public void close() {
        mDbHelper.close();
    }
 
	public boolean isTable1Empty() {
		return mCharactersDbHelper.isEmpty();
	}
}
une classe pour la table 1:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Table1DbAdapter {
 
    private SQLiteDatabase mDb;
 
    public Table1DbAdapter(SQLiteDatabase sqldb) {
        this.mDb = sqldb;
    }
 
    public boolean isEmpty() {
    	Cursor tmpCurs = mDb.query(TABLE_NAME, new String[] {KEY_ROWID}, null, null, null, null, null);
    	int nbChars = tmpCurs.getCount();
    	tmpCurs.close();
        return (nbChars == 0);
    }
}
Vous remarquerez la dernière fonction isEmpty : c'est elle qui me pose problème.

En effet, si je la code comme dans ma toute première classe, j'ai une erreur (pour une raison que j'ignore):
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
    public boolean isEmpty() {
        return (mDb.query(TABLE_NAME, new String[] {KEY_ROWID}, null, null, null, null, null).getCount() == 0);
    }
Donne à l'exécution ceci:
11-15 18:09:24.134: INFO/dalvikvm(1569): Uncaught exception thrown by finalizer (will be discarded):
11-15 18:09:24.134: INFO/dalvikvm(1569): Ljava/lang/IllegalStateException;: Finalizing cursor android.database.sqlite.SQLiteCursor@437427e8 on table1 that has not been deactivated or closed
11-15 18:09:24.134: INFO/dalvikvm(1569): at android.database.sqlite.SQLiteCursor.finalize(SQLiteCursor.java:596)
11-15 18:09:24.134: INFO/dalvikvm(1569): at dalvik.system.NativeStart.run(Native Method)
D'où ma bidouille pour pouvoir explicitement fermer le curseur, ce qui fonctionne... Mais je ne comprends pas pourquoi cette méthode marche dans un cas et pas dans l'autre... enfin, ça marche, mais j'ai un warning...

D'où mes 2 questions:

1. comment gérez-vous plusieurs tables ?
2. quelqu'un peut-il m'expliquer pourquoi ça marche moins bien dans le second cas que dans le premier ?